2016-06-16 9 views
2

Ich benutze VC14 und Boost-Version ist 1.60.Kompilierfehler auf boost :: bind (Elementfunktion) in Spirit-Parser-Aktion auf Kontextargument

#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-Fehler:

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>> ' 

Ich habe einen Weg zu bekommen, was fand ich will mit ‚Hold‘ Richtlinie aber ich weiß nicht, Art und Weise Code mit boost :: bind mit Kontext nicht der Fall ist kompilieren. Ich bin offen für eine Lösung mit Phoenix-Nutzung.

+0

FYI, es nie einen Grund ist 'steigern zu verwenden :: bind' seit C++ 11 –

+0

Wenn ich std :: bind (& str_menager verwendet haben: : entscheiden, & controler, std :: placeholders :: _ 1, std :: placeholders :: _ 2, std :: placeholders :: _ 3) Ich habe: 'Fehler C2338: Tupel Index außerhalb der Grenzen' und funktioniert immer noch nicht –

+0

@TypeTraitor Ich wollte protestieren, aber anscheinend haben Sie Recht . Es gibt jedoch [einige Dinge, die 'std :: bind '] (http://melpon.org/wandbox/permlink/hrOWxOiDpiLhwVjX) erlaubt, dass man mit einem Lambda vor C++ 14 nicht machen kann. – llonesmiz

Antwort

0

an den Körper Ihres decide Mitglied Funktion Suchen müssen Sie vier Dinge:

  • ein qi::symbols<char> vistring, die str_menager gehört (und damit kein Parameter sein muss).
  • eine std::string s das ist das Attribut name.
  • ein std::list<std::string> das ist das Attribut stringslist.
  • Ein bool m_Flag, mit dem Sie einen Fehler beim Parsen signalisieren können.

    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; 
        } 
    } 
    

    und sollte aufgerufen werden:

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

    Das Problem ist, dass seit decide ist ein Funktionselement die Funktion Anpassung Phoenix

So ideal Ihre decide Member-Funktion einfach sein sollte, Makros funktionieren nicht direkt (und definieren Sie Ihre eigenen phoenix::function ist eine Menge Boilerplate).

One workaround could be using:

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

Beachten Sie, dass Sie benötigen 4 passieren (nicht 3), um zu berücksichtigen, die Notwendigkeit, auch eine Instanz von str_menager (und zu diesem Thema übergeben müssen Sie controler eine machen Mitglied Ihrer Grammatik, da in Ihrem Beispiel die Lebensdauer endet, wenn der Konstruktor fertig ist, aber Sie versuchen, es lange danach zu verwenden). Hier

ist die vollständige Beispiel: (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: Es sei denn, dies ein vereinfachtes Beispiel ist, und Sie planen, viel mehr in Ihrem str_menager Struktur zu tun, könnten Sie einfach definieren decide als freie Funktion und vistring direkt als Parameter übergeben, das heißt:

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

Vielen Dank für deine Phoenix Lektion, es ist hilfreich für mich :-) –