2013-11-12 1 views
6

Моя цель - создать временное решение, чтобы я мог использовать lambdas C++ 11 внутри смысловых действий Boost Spirit Qi, доступ к более расширенному набору заполнителей qi, таких как qi :: _ pass или qi :: _ r1, без необходимости вручную извлекать их из контекстного объекта. Я хочу избежать написания Phoenix lambdas для некоторой нетривиальной логики синтаксического анализа, предпочитая более прямой синтаксис C++ и семантику, доступную внутри C++ 11 lambdas.Phoenix :: bind для C++ 11 lambdas в boost :: spirit :: qi семантические действия

В приведенном ниже коде представлена ​​идея, которую я использую для обходного пути. Идея состоит в том, чтобы использовать phoenix :: bind для привязки к лямбда и передать ей конкретные заполнители, которые мне нужны. Тем не менее, я получаю чрезвычайно длинную templated ошибку компилятора (gcc 4.7.0, Boost 1.54), что у меня нет опыта для интерпретации. Я выбрал то, что, по моему мнению, является наиболее важной частью и разместил его под кодом.

Я хотел бы знать, возможно ли, что я пытаюсь сделать в этом коде, с Boost Spirit, и если кто-нибудь может интерпретировать сообщение об ошибке для меня и сказать мне, что происходит не так.

#include <string> 
#include <iostream> 

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

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

int main() { 

    std::string input{"test1 test2 test3 FOO!"}; 
    typedef decltype(input.begin()) StringIter; 

    qi::rule<StringIter, std::string()> parser = 
     *(
      qi::char_ 
      [ 
       phoenix::bind(
        [] (char value) { 
         std::cerr << value << std::endl; 
        }, 
        qi::_1 
       ) 
      ] 
     ); 

    qi::parse(input.begin(), input.end(), parser); 
} 

(Примечание: Я знаю, что конкретная задача, выполняемая этот код будет проще с прямыми конструкциями Феникса, или может даже быть сделана благодаря обновлениям Boost Духа, которые позволяют одноаргументный C++ 11 lambda напрямую, так как он использует только разобранное значение (qi :: _ 1). Тем не менее, это хороший минимальный пример того, что я хотел бы сделать, и если я могу заставить его работать, он должен легко обобщать .)

И, немного ошибки компилятора (через STLfilt):

test\testSpiritLearning.cpp:28:9: required from here 
D:\programming\lib\boost\boost_1_54_0/boost/spirit/home/support/action_dispatch.hpp:178:13: 
error: no match for call to '(
    const boost::phoenix::actor< 
     boost::phoenix::composite< 
      boost::phoenix::detail::function_eval<1> 
      , boost::fusion::vector< 
       boost::phoenix::value<main()::<lambda(char &)> > 
       , boost::spirit::argument<0>, boost::fusion::void_ 
       , boost::fusion::void_, boost::fusion::void_ 
       , boost::fusion::void_, boost::fusion::void_ 
       , boost::fusion::void_, boost::fusion::void_ 
       , boost::fusion::void_ 
      > 
     > 
    > 
) (
    boost::spirit::traits::pass_attribute< 
     boost::spirit::qi::char_class< 
      boost::spirit::tag::char_code< 
       boost::spirit::tag::char_ 
       , boost::spirit::char_encoding::standard 
      > 
     >, char, void 
    >::type & 
    , boost::spirit::context< 
     boost::fusion::cons<basic_string<char> &, boost::fusion::nil> 
     , boost::fusion::vector0<> 
    > &, bool & 
)' 

ответ

4

Просто скажите подталкивание, что вы хотите кровоточивость поддержку края компилятора: [1]

#define BOOST_RESULT_OF_USE_DECLTYPE 

и вы хотите использовать версию V3 Феникс:

#define BOOST_SPIRIT_USE_PHOENIX_V3 

И это работает

Посмотреть его Live on Coliru

Причина:

  • Использование объектов в функции Phoenix актеров принимают ваш объект функции будет иметь специальный вложенную struct result шаблон или действительно простые ЬурейеЕ result_type. Это известно как протокол RESULT_OF, смотрите здесь:

    http://www.boost.org/doc/libs/1_55_0/libs/utility/utility.htm#result_of

    Этот протокол необходим для совместимости с ++ 03. Тем не менее, lambdas не имеет. Фактически, lambdas имеют неуказанные типы. Это именно одна из причин, почему компиляторы с поддержкой лямбдах всегда будут иметь decltype, так что протокол RESULT_OF больше не требуется

  • На втором #define, вам нужно выбрать Phoenix V3, потому что Phoenix V2 просто Безразлично «Внедрение поддержки лямбда. По умолчанию Spirit V2 выбирает Phoenix V2 по причинам истории/совместимости.На практике, Phoenix V3 только гораздо более зрелым и исправляет многие (много много) проблем, поэтому я рекомендую всегда работает с BOOST_SPIRIT_USE_PHOENIX_V3


[1] не могут быть необходимы с совсем недавно версии некоторых компиляторов

+0

Большое спасибо, что действительно исправляет ошибки компилятора. Из любопытства я также пробовал это с каждым дополнением, которое было прокомментировано по очереди; но он работал только с обоими комментариями. Теперь мне любопытно понять, с кем это работает. –

+0

@anthrond Конечно, я упомянул _both_ по какой-то причине :) Я добавил небольшое объяснение. Cheers – sehe

+0

Отлично, ваше объяснение объясняет это мне. –