стимулируйте дух семантических действий и типов данных слияния

У меня есть правило, которое должно возвращать Boost.Fusion ASSOC_STRUCT. Я пытаюсь присвоить _val результаты, проанализированные синтаксическими анализаторами правила, но я не могу заставить его работать. Я пропущу разговор и представлю вам непосредственно соответствующий код.

#include <boost/fusion/include/define_assoc_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/spirit/include/qi_symbols.hpp>
#include <iostream>
#include <string>

namespace keys {
struct actor_key;
struct action_key;
struct money_key;
}

BOOST_FUSION_DEFINE_ASSOC_STRUCT(
(), ActionLine,
(int, action, keys::action_key)
(int, amount, keys::money_key)
(int, actor, keys::actor_key)
)

int main ()
{
namespace qi = boost::spirit::qi;
using qi::_1;
using qi::_2;
using qi::_a;
using qi::int_;
using qi::lit;
using boost::spirit::_val;
using boost::fusion::as_vector;

qi::symbols<char, int> name_parser_;
name_parser_.add("name4", 4);

std::string input("string1 ($7) string2 name4");
std::string::const_iterator f(input.begin()), l(input.end());
ActionLine expected{0, 7, 4}, result;

//The following rule is supposed to parse input of the form
//"string1 ($[integer]) string2 [name]"//and return a triple (ActionLine) with the values { 0, value of (int_), value of (name_parser_) }
qi::rule<std::string::const_iterator, ActionLine()> action_line_ =
lit("string1 ($") >> int_ >> lit(") string2 ") >> name_parser_
// [ _val = ActionLine{0, _1, _2} ]; // this is what I am trying to achieve
[ _val = ActionLine{0, 7, 4} ]; //this compiles, but of course is not what I need

bool b =
qi::parse(f, l, action_line_, result) &&
as_vector(result) == as_vector(expected);

std::cout << "test: " << std::boolalpha << b << std::endl;
return 0;
}

(Компилировать с помощью g ++ выше_file.cpp -std = c ++ 0x)
Ошибка компилятора в моем реальном приложении несколько отличается от ошибки в этом примере, но это что-то вроде (в строке _val = ActionLine {0, _1, _2}):
Нет соответствующей функции call :: ActionLine :: ActionLine (), и я думаю, что она не может конвертировать _1 и _2 в целые.

Я также пытался добавить локальные переменные int и использовать их для копирования проанализированных значений, но это не сработало, не с помощью boost :: phoenix :: at (_1,0), boost :: phoenix :: at (_1,1 ) (Я нашел эти идеи здесь повысить дух семантических параметров действия)

1

Решение

Вам нужно использовать phoenix::construct в вашем семантическом действии делать то, что вы хотите.

#include <boost/fusion/include/define_assoc_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp> //CHANGE:you need to include this to use "phoenix::construct"#include <boost/fusion/include/as_vector.hpp>
#include <boost/spirit/include/qi_symbols.hpp>
#include <iostream>
#include <string>

namespace keys {
struct actor_key;
struct action_key;
struct money_key;
}

BOOST_FUSION_DEFINE_ASSOC_STRUCT(
(), ActionLine,
(int, action, keys::action_key)
(int, amount, keys::money_key)
(int, actor, keys::actor_key)
)

int main ()
{
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
using qi::_1;
using qi::_2;
using qi::_a;
using qi::int_;
using qi::lit;
using boost::spirit::_val;
using boost::fusion::as_vector;

qi::symbols<char, int> name_parser_;
name_parser_.add("name4", 4);

std::string input("string1 ($7) string2 name4");
std::string::const_iterator f(input.begin()), l(input.end());
ActionLine expected{0, 7, 4}, result;

//The following rule is supposed to parse input of the form
//"string1 ($[integer]) string2 [name]"//and return a triple (ActionLine) with the values { 0, value of (int_), value of (name_parser_) }
qi::rule<std::string::const_iterator, ActionLine()> action_line_ =
(lit("string1 ($") >> int_ >> lit(") string2 ") >> name_parser_) //CHANGE:the parentheses are important otherwise the semantic action would be attached to name_parser_
[ _val = phx::construct<ActionLine>(0, _1, _2) ]; //CHANGE: you need to use phoenix to use the placeholders _1, _2, etc

bool b =
qi::parse(f, l, action_line_, result) &&
as_vector(result) == as_vector(expected);

std::cout << "test: " << std::boolalpha << b << std::endl;
std::cout << at_key<keys::action_key>(result)<< ", " << at_key<keys::money_key>(result)<< ", " << at_key<keys::actor_key>(result) << std::endl;

return 0;
}
2

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

Других решений пока нет …