2014-11-21 2 views
2

Я изучаю boost :: spirit и столкнулся с путаницей, что семантическое действие оценивается во время построения грамматики. Следующий код выводит:Семантическое действие, оцененное в конструкторе грамматики (или нет?)

string= 

Мое предположение, что этот вывод как часть семантического действия прилагается к orule.

Есть ли способ избежать такого поведения? или это то, с чем мне нужно будет жить, если я использую std::cout в семантическом действии?

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <iostream> 
#include <string> 

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

template <typename Iterator> 
    struct my_grammar : qi::grammar<Iterator, std::string() > 
{ 
    my_grammar() : my_grammar::base_type(orule) 
    { 
     using qi::_1; 
     using qi::_2; 
     using qi::attr; 
     using qi::string; 
     using phx::val; 

     orule = string("abc") [ std::cout << "string=" << _1 << std::endl ]; 
    } 
    qi::rule< Iterator, std::string() > orule; 
}; 

int main() 
{ 
    typedef std::string::const_iterator iterator_type; 
    typedef my_grammar<iterator_type> parser; 
    parser my_parser; // Our grammar 
    return 0; 
} 

ответ

3

Короткий ответ: Нет, семантические действия не оценивали во время инициализации правила.

Однако ваша проблема заключается в том, что вы не просто (просто) создали семантическое действие.


Да, в вашем случае первая часть этого выражения

std::cout << "string=" << _1 << std::endl 

имеет побочный эффект: (std::cout << "string=") вставляет буквальным в стандартный объект ostream и затем возвращаетstd::cout посредством ссылки.

Это потому, что вы используете std::operator<<, определенные в стандартной библиотеке, а не boost::phoenix::....::operator<< ¹.


Вы можете исправить это форсирования тип второго аргумента то, что будет выбрать правильную перегрузку:

std::cout << phx::val("string=") << _1 << std::endl 

Конечно, вы всегда можете сделать вдвойне уверены, делая, например,

phx::ref(std::cout) << _1 << std::endl 

Но вы заметите, что люди склонны пропускать это, когда это возможно. Второй операнд boost::spirit::_1 уже индуцирует контекст выражения-шаблона (т. Е. Выбирает нестандартные перегрузки операторов, которые создают ленивых участников вместо побочного эффекта).


¹ что, вероятно, в конечном итоге просто быть boost::proto::....::operator<< так или иначе, но это все вкусные детали реализации :)

+0

Спасибо за ваш ответ - это дало мне дальнейшее понимание того, что происходит на самом деле в этих семантических действий – Jimmy