boost::spirit:: карма Генератор семантических действий в правилах
Это мучило меня часами, и я не понимаю, как заставить это работать. Я просто хочу что-то делать каждый раз, когда используется правило, в этом примере увеличивать счетчик. Если я не указываю явно правило, но использую его в вызове boost::spirit::karma::generate, оно работает. Но когда я пытаюсь поместить все в правило, оно не скомпилируется, и я не получаю никакой информации из длинного сообщения об ошибке.
#include <iostream>
#include <string>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
int main()
{
using boost::spirit::karma::eps;
using boost::spirit::karma::int_;
using boost::spirit::karma::lit;
using boost::spirit::karma::eol;
using boost::phoenix::val;
using boost::phoenix::ref;
using boost::spirit::karma::generate;
using boost::spirit::karma::rule;
typedef std::back_insert_iterator<std::string> OutputIteratorType;
std::string s;
std::back_insert_iterator<std::string> sink(s);
int lineNum = 0;
generate(sink, eps[ref(lineNum) += 10] << lit("Line number ") << lit(lineNum) << lit(": ") << int_ << eol, 123);
generate(sink, eps[ref(lineNum) += 10] << lit("Line number ") << lit(lineNum) << lit(": ") << int_ << eol, 123);
// Will not compile
//rule<OutputIteratorType, int()> testRule = eps[ref(lineNum) += 10] << lit("Line number ") << lit(lineNum) << lit(": ") << int_ << eol;
//generate(sink, testRule, 123);
//generate(sink, testRule, 123);
std::cout << s;
return 0;
}
(Выше вы можете увидеть версию boost:: spirit, которая является самой элегантной, но при использовании лямбда-функции или функции-члена все получается одинаково, "прямой метод" работает, а "метод правила" - нет.)
К сожалению, я также не могу найти какую-либо документацию или примеры или другие ресурсы, которые покрывают это, я был бы очень благодарен за ссылки тоже.
1 ответ
Это проблема с boost::phoenix V2 (не спрашивайте, какая;-)) Итак, использование V3 будет работать.
Кроме того, необходимо дать атрибут генератору int и ссылаться на lineNum при его печати.
#include <iostream>
#include <string>
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
int main() {
using boost::spirit::karma::eps;
using boost::spirit::karma::int_;
using boost::spirit::karma::lit;
using boost::spirit::karma::eol;
using boost::spirit::karma::_1;
using boost::spirit::karma::_val;
using boost::phoenix::val;
using boost::phoenix::ref;
using boost::spirit::karma::generate;
using boost::spirit::karma::rule;
typedef std::back_insert_iterator<std::string> OutputIteratorType;
std::string s;
std::back_insert_iterator<std::string> sink(s);
int lineNum = 0;
rule<OutputIteratorType, int()> testRule = eps[ref(lineNum) += 10]
<< lit("Line number ") << lit(ref(lineNum)) << lit(": ")
<< int_[_1 = _val] << eol;
generate(sink, testRule, 123);
generate(sink, testRule, 123);
std::cout << s;
return 0;
}