2016-06-16 7 views
2

Я использую vc14, а boost - 1.60.Ошибка компиляции в boost :: bind (функция-член) в действии синтаксического анализа на аргумент контекста

#include <boost/config/warning_disable.hpp> 
#include <boost\spirit\home\qi.hpp> 
#include <boost\variant.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> 
#include <boost/phoenix/function/adapt_function.hpp> 
#include <boost\spirit\include\phoenix_fusion.hpp> 
#include <boost\foreach.hpp> 
#include <string> 
#include <list> 
#include <boost\bind.hpp> 
#define BOOST_SPIRIT_USE_PHOENIX_V3 


namespace testParser { 
     namespace qi = boost::spirit::qi; 
     namespace ascii = boost::spirit::ascii; 
     namespace sp = boost::spirit; 
     namespace fu = boost::fusion; 
     typedef sp::context< 
      fu::cons<std::list<std::string>,fu::nil >, 
      fu::vector0<> 
     > context; 

     class str_menager 
     { 
      qi::symbols<char> const& vistrings; 

     public: 
      typedef void result_type; 
         typedef void type; 
      str_menager(qi::symbols<char> const& ss) :vistrings(ss) { } 
      void operator()(std::string const& s, context& con, bool& m_Flag) 
      { 
       if (vistrings.find(s) != nullptr) 
       { 
        using boost::phoenix::at_c; 
        (fu::at_c<0>(con.attributes)).push_back(s); 
       } 
       else 
       { 
        m_Flag = false; 
       } 
      } 
      void decide(std::string const& s, 
//    boost::spirit::qi::unused_type , 
       context& con, 
       bool& m_Flag) 

      { 
       if (vistrings.find(s) != nullptr) 
       { 
        using boost::phoenix::at_c; 
        (fu::at_c<0>(con.attributes)).push_back(s); 
       } 
       else 
       { 
        m_Flag = false; 
       } 
      } 
     }; 



     typedef std::list<std::string> strings; 
     template <typename iterator, typename Skiper = ascii::space_type> 
     struct stringParser :qi::grammar <iterator, strings(), Skiper> 
     { 
      stringParser() : stringParser::base_type(stringslist) { 
       using boost::phoenix::at_c; 
       using boost::spirit::qi::_val; 
       using boost::spirit::qi::int_; 



       using boost::spirit::qi::omit; 
       using boost::spirit::qi::lexeme; 
       using boost::spirit::ascii::alpha; 
       using boost::spirit::qi::raw; 
       using boost::spirit::qi::fail; 
       using boost::spirit::_pass; 
       using boost::spirit::false_; 
       using boost::spirit::qi::on_error; 
       using boost::phoenix::val; 
       using boost::phoenix::construct; 
       using boost::phoenix::ref; 
       using boost::spirit::hold; 


       str_menager controler(vistrings); 
       name = raw[lexeme[*alpha]]; 
       stringslist = 
        *(
         omit[("VIS" > name)[ref(vistrings) += qi::_1] 
         ] | 
         //hold[ 
          name 
         //] > vistrings 
         [boost::bind(&str_menager::decide, &controler, _1, _2, _3)] 
         ) 
        ; 
       name.name("some_name"); 
       stringslist.name("stringslist"); 
       on_error<fail> 
        (stringslist, 
         std::cout << val("Error! Expectiong ") 
         << qi::_4 
         << val(" here: \"") 
         << construct<std::string>(qi::_3, qi::_2) 
         << val("\"") 
         << std::endl); 
      } 
      qi::symbols<char> vistrings; 
      qi::rule<iterator, strings(), ascii::space_type> stringslist; 
      qi::rule<iterator, std::string(), ascii::space_type> name; 



     }; 
    } 

void TestSS() 
{ 
    std::string str = " VIS someString someString otherString"; 
    typedef std::string::const_iterator iterator_type; 
    typedef testParser::stringParser<iterator_type> stringParser; 

    stringParser strParser; 

    iterator_type end = str.end(); 
    iterator_type iter = str.begin(); 

    testParser::strings strings; 
    int i = 0; 
    boost::spirit::ascii::space_type sp; 
    bool r = boost::spirit::qi::phrase_parse(iter, end, strParser, sp, strings); 

    BOOST_FOREACH(std::string const& p, strings) 
    { 
     std::cout << p << "\n"; 
    } 

    std::cout << "\n"; 

} 

Compiler ошибка:

Error C2664 'void boost::_mfi::mf3<void,testParser::str_menager,const std::string &,testParser::context &,bool &>::operator()(T *,A1,A2,A3) const': cannot convert argument 3 from 
'boost::spirit::context<boost::fusion::cons<std::list<std::string,std::allocator<_Ty>> ,boost::fusion::nil_>,boost::fusion::vector0<void>>' to 
'boost::spirit::context<boost::fusion::cons<std::list<std::string,std::allocator<_Ty>>,boost::fusion::nil>,boost::fusion::vector0<void>> ' 

Я нашел способ, чтобы получить то, что я хочу, используя директиву «Hold», но я не знаю путь кода повышающего :: связывают с контекстом не компиляции. Я открыт для решения с использованием феникса.

+0

FYI, там никогда не повод использовать 'повышение :: bind' поскольку C++ 11 –

+0

Когда я использовал станд :: безвыходном (& str_menager: : define, & controler, std :: placeholders :: _ 1, std :: placeholders :: _ 2, std :: placeholders :: _ 3) У меня есть: 'ошибка C2338: tuple index out of bounds' и до сих пор не работает –

+0

@typetraitor Я собирался протестовать, но, видимо, вы правы , Есть, однако, [некоторые вещи, которые 'std :: bind'] (http://melpon.org/wandbox/permlink/hROWxOiDpiLhwVjX) позволяют вам не делать с лямбдой до C++ 14. – llonesmiz

ответ

0

Глядя на тело вашей функции decide члена вам нужны четыре вещи:

  • qi::symbols<char> vistring который принадлежит str_menager (и, следовательно, не нужно быть параметром).
  • a std::string s, который является атрибутом name.
  • a std::list<std::string> который является атрибутом stringslist.
  • a bool m_Flag, который позволяет сигнализировать о сбое при разборе.

Так в идеале ваша decide функция-член должно быть просто:

void define(const std::string& s, std::list<std::string>& list, bool& m_Flag) 
{ 
    if (vistrings.find(s) != nullptr) 
    { 
     list.push_back(s); 
    } 
    else 
    { 
     m_Flag = false; 
    } 
} 

и должен быть вызван:

name[adapted_decide(qi::_1,qi::_val,qi::_pass)] 

Проблема заключается в том, что, поскольку decide функция член адаптация функции Phoenix макросы не работают напрямую (и определение вашего собственного phoenix::function - это много шаблонов).

One workaround could be using:

BOOST_PHOENIX_ADAPT_FUNCTION(void,decide_,boost::mem_fn(&str_menager::decide),4); 

Обратите внимание, что вам необходимо пройти 4 (не 3) для того, чтобы принять во внимание необходимость также передать экземпляр str_menager (и по этому вопросу вам нужно сделать controler в член вашей грамматики, так как в вашем примере его время жизни заканчивается, когда конструктор завершается, но вы пытаетесь использовать его после этого).

Вот полный пример: (Running on Coliru)

#include <boost/config/warning_disable.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/variant.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 
#include <boost/spirit/include/phoenix_function.hpp> 
#include <boost/spirit/include/phoenix_fusion.hpp> 
#include <boost/spirit/include/phoenix_object.hpp> 
#include <boost/foreach.hpp> 
#include <string> 
#include <list> 
#include <boost/mem_fn.hpp> 


namespace testParser { 
     namespace qi = boost::spirit::qi; 
     namespace ascii = boost::spirit::ascii; 
     namespace sp = boost::spirit; 
     namespace fu = boost::fusion; 
     namespace phx = boost::phoenix; 


     class str_menager 
     { 
      qi::symbols<char> const& vistrings; 

     public: 
      typedef void result_type; 
         typedef void type; 
      str_menager(qi::symbols<char> const& ss) :vistrings(ss) { } 


      void decide(std::string const& s, 
       std::list<std::string>& list, 
       bool& m_Flag) 

      { 
       if (vistrings.find(s) != nullptr) 
       { 
        list.push_back(s); 
       } 
       else 
       { 
        m_Flag = false; 
       } 
      } 
     }; 

     BOOST_PHOENIX_ADAPT_FUNCTION(void,decide_,boost::mem_fn(&str_menager::decide),4);//you need to put here number_of_args+1 to take into account the instance parameter 



     typedef std::list<std::string> strings; 
     template <typename iterator, typename Skiper = ascii::space_type> 
     struct stringParser :qi::grammar <iterator, strings(), Skiper> 
     { 
      stringParser() : stringParser::base_type(stringslist),vistrings(),controler(vistrings) { 
       using boost::spirit::qi::omit; 
       using boost::spirit::qi::lexeme; 
       using boost::spirit::ascii::alpha; 
       using boost::spirit::qi::raw; 
       using boost::spirit::qi::fail; 
       using boost::spirit::qi::on_error; 
       using phx::val; 
       using phx::ref; 
       using phx::construct; 


       name = raw[lexeme[*alpha]]; 
       stringslist = 
        *(
         omit[("VIS" > name)[ref(vistrings) += qi::_1] 
         ] | 
          name 
         [decide_(&controler, qi::_1, qi::_val, qi::_pass)] 
         ) 
        ; 
       name.name("some_name"); 
       stringslist.name("stringslist"); 
       on_error<fail> 
        (stringslist, 
         std::cout << val("Error! Expectiong ") 
         << qi::_4 
         << val(" here: \"") 
         << construct<std::string>(qi::_3, qi::_2) 
         << val("\"") 
         << std::endl); 
      } 
      qi::symbols<char> vistrings; 
      str_menager controler; 
      qi::rule<iterator, strings(), ascii::space_type> stringslist; 
      qi::rule<iterator, std::string(), ascii::space_type> name; 



     }; 
    } 

void parse(const std::string& str) 
{ 
    typedef std::string::const_iterator iterator_type; 
    typedef testParser::stringParser<iterator_type> stringParser; 

    stringParser strParser; 

    iterator_type end = str.end(); 
    iterator_type iter = str.begin(); 

    testParser::strings strings; 
    boost::spirit::ascii::space_type sp; 
    bool r = boost::spirit::qi::phrase_parse(iter, end, strParser, sp, strings); 
    if(r) 
    { 
     std::cout << "Success.\n"; 
     BOOST_FOREACH(std::string const& p, strings) 
     { 
      std::cout << p << "\n"; 
     } 
    } 
    else 
    { 
     std::cout << "Something failed.\n"; 
    } 
    if(iter!=end) 
    { 
     std::cout << "Unparsed: [" << std::string(iter,end) << "]"; 
    } 

    std::cout << std::endl; 
} 

int main() 
{ 
    parse(" VIS someString someString otherString"); 
    parse("VIS foo VIS bar foo bar baz"); 
    parse("VIS foo bar foo VIS bar baz"); 
} 

PS: Если это не упрощенный пример, и вы планируете делать много больше в вашем str_menager структуры, вы могли бы просто определить decide как свободная функция и передать vistring непосредственно в качестве параметра, а именно:

void decide(const qi::symbols<char>& vistring, const std::string& s, std::list<std::string>& list, bool& m_Flag) 
{ 
    //same as before 
} 
BOOST_PHOENIX_ADAPT_FUNCTION(void,decide_,decide,4); 
... 
name[decide_(phx::ref(vistring),qi::_1,qi::_val,qi::_pass)] 
... 
+0

Очень спасибо за урок феникса, это полезно для меня :-) –

 Смежные вопросы

  • Нет связанных вопросов^_^