Boost Spirit: как конвертировать основные типы?

Предположим, у меня есть std::string атрибут, но для простоты разбора, я хотел бы использовать qi::int_ или же qi::double_,

Есть ли простой способ сделать преобразование как семантическое действие??

Я попробовал что-то вроде этого:

 std::stringstream ss;
my_int_as_str = qi::int_ [ ref(ss)<<_1; _val=ss.str() ];

но это даже не скомпилируется.

РЕДАКТИРОВАТЬ — попытаться с ответом sehe ниже

#include <iostream>
#include <string>
#include <vector>

#include <boost/spirit/include/qi.hpp>

namespace qi=boost::spirit::qi;
namespace phx=boost::phoenix;

int main(int argc, char* argv[])
{
std::string test="123";
std::string result;

// 1. qi::raw[ qi::int_ ]       works
// 2. qi::lexeme[ qi::int_ ]    doesn't
// 3. qi::as_string[ qi::int_ ] doesn't
qi::rule<std::string::const_iterator, std::string()> my_int_as_str =
qi::raw[ qi::int_ ];
parse( test.cbegin(), test.cend(), my_int_as_str, result );

std::cout << result << std::endl;

// -------------------------------------------------------------------------

std::string test_vector="456 789";
std::vector<std::string> result_vector;

// 4. qi::raw[ qi::int_ ]       won't compile
// 5. qi::lexeme[ qi::int_ ]    won't compile
// 6. qi::as_string[ qi::int_ ] doesn't
qi::rule<std::string::const_iterator,std::vector<std::string>(),qi::space_type>
my_int_as_str_vector = qi::lexeme[ qi::int_ ];

phrase_parse(test_vector.cbegin(),test_vector.cend(),
my_int_as_str_vector,qi::space,result_vector);

for(auto& string: result_vector)
std::cout << string << std::endl;

return 0;
}

3

Решение

Ты можешь использовать attr_cast специализируясь transform_attribute для ваших типов.

#include <iostream>
#include <string>
#include <vector>

#include <boost/spirit/include/qi.hpp>

namespace qi=boost::spirit::qi;
namespace phx=boost::phoenix;namespace boost { namespace spirit { namespace traits
{

template <>
struct transform_attribute<std::string, int, qi::domain>
{
typedef int type;
static int pre(std::string& d) { return 0; }//not useful in this case but required to avoid compiler errors
static void post(std::string& val, int const& attr) //`val` is the "returned" string, `attr` is what int_ parses
{
std::stringstream ss;
ss << attr;
val= ss.str();
}
static void fail(std::string&) {}
};
}}}

int main(int argc, char* argv[])
{
std::string test="123";
std::string test_vector="456 789";

qi::rule<std::string::const_iterator,std::string()> my_int_as_str = qi::attr_cast(qi::int_);
qi::rule<std::string::const_iterator,std::vector<std::string>(),qi::space_type> my_int_as_str_vector= *qi::attr_cast(qi::int_);

std::string result;
std::vector<std::string> result_vector;

parse(test.cbegin(),test.cend(),my_int_as_str,result);
phrase_parse(test_vector.cbegin(),test_vector.cend(),my_int_as_str_vector,qi::space,result_vector);std::cout << result << std::endl;
for(auto& string: result_vector)
std::cout << string << std::endl;return 0;
}

Если вам действительно нужно / хотите использовать семантические действия простейшей альтернативой было бы определение функции, принимающей int в качестве аргумента и возвращающей строку (это проще, чем attr_cast альтернатива, но она также медленнее, почти вдвое быстрее в моих действительно простых тестах):

std::string semantic_transform(int i)
{
std::stringstream ss;
ss<<i;
return ss.str();
}
...
std::string string_semantic;
qi::parse(test.cbegin(),test.cend(),qi::int_[&semantic_transform],string_semantic);
std::cout << string_semantic << std::endl;
6

Другие решения

Встроенный способ:

qi::rule<Iterator, std::string()> my_int_as_str =
qi::as_string [ qi::int_ ];

Для этого конкретного простого случая, qi::raw или же qi::lexeme работал бы одинаково хорошо, так как они обе выставляют пары источник-итератор, которые имеют встроенные Назначение к атрибуту за std::string

Разрабатывая:

my_int_as_str = qi::lexeme [ qi::int_ ]; // equivalent
my_int_as_str = qi::raw [ qi::int_ ];    // idem
6

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector