c++ - Boost spirit: Invalidate parser from member function -


this article (boost spirit semantic action parameters) explains how invalidate match plain function signature

void f(int attribute, const boost::fusion::unused_type& it, bool& mflag) 

i invalidate match member function of grammar:

#include <boost/spirit/home/qi.hpp> #include <boost/spirit/home/phoenix.hpp>  #include <iostream> #include <string>  namespace qi  = boost::spirit::qi; namespace phoenix = boost::phoenix;   class moduleaccessmanager { public:     bool getmodule(const std::string name)     {         if(name == "cat" || name == "dog")             return true;         else             return false;     } };  void globalismodule(std::string modulename, const boost::spirit::unused_type&, bool& mflag) {         moduleaccessmanager acm; /* dirty workaround example */         if(acm.getmodule(modulename))             std::cout << "[ismodule] info: found module name >"  << modulename << "<" << std::endl;         else         {             std::cout << "[ismodule] error: no module name >" << modulename << "<" << std::endl;             mflag = false; // no valid module name         } }   template <typename iterator, typename skipper> class modulecommandparser : public qi::grammar<iterator, skipper> { private:     moduleaccessmanager* m_acm;      qi::rule<iterator, skipper> start, module;  public:     std::string m_modulename;      modulecommandparser(moduleaccessmanager* acm)         : modulecommandparser::base_type(start)         , m_acm(acm)         , m_modulename("<empty>")     {         module  =   qi::as_string[qi::lexeme[+(~qi::char_(' '))]]             [&globalismodule] // works fine //          [phoenix::bind(&modulecommandparser::ismodule, this)] // compile error             ;         start    =  module >> qi::as_string[+(~qi::char_('\n'))];     };      void ismodule(std::string modulename, const boost::spirit::unused_type&, bool& mflag)     {         // check if module modulename exists         if(m_acm->getmodule(modulename))             std::cout << "[ismodule] info: found module name >"  << modulename << "<" << std::endl;         else         {             std::cout << "[ismodule] error: no module name >" << modulename << "<" << std::endl;             mflag = false; // no valid module name         }     };  };   int main() {     moduleaccessmanager acm;     modulecommandparser<std::string::const_iterator, qi::space_type> commandgrammar(&acm);      std::string str;     std::string::const_iterator first;     std::string::const_iterator last;      str = "cat run";     first = str.begin();     last = str.end();     qi::phrase_parse(first, last, commandgrammar, qi::space);      str = "bird fly";     first = str.begin();     last = str.end();     qi::phrase_parse(first, last, commandgrammar, qi::space); } 

code on coliru: http://coliru.stacked-crooked.com/a/4319b38a6d36c362

the important part these 2 lines:

            [&globalismodule] // works fine //          [phoenix::bind(&modulecommandparser::ismodule, this)] // compile error 

using global function works fine, that's not option me because need access m_acm object specific parser.

how can bind member function semantic action , @ same time able invalidate match member function (using 3 argument function signature mentioned above)?

there 2 ways:

  • you can assign qi::_val using phoenix actors
  • you can assign third parameter (bool&) inside "raw" semantic action function

an example here:

the anatomy of semantic action function (with third argument):


in case have member function "raw semantic action function" signature. of course, you'll have bind this parameter (because it's non-static member function).

note in particular case, phoenix::bind not right bind use, phoenix actors considered "cooked" (not raw) semantic actions, , executed in spirit context.

you either

  1. use boost::bind (or std::bind) bind function preserves arity (!) of member function:

    [boost::bind(&modulecommandparser::ismodule, this, ::_1, ::_2, ::_3)] 

    this works: live on coliru

  2. instead use "cooked" semantic action, directly assigning _pass context placeholder:

    [qi::_pass = phoenix::bind(&moduleaccessmanager::getmodule, m_acm, qi::_1)] 

    this works too: live on coliru

the latter example, future reference:

#define boost_spirit_use_phoenix_v3 #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp>  #include <iostream> #include <string>  namespace qi      = boost::spirit::qi; namespace phoenix = boost::phoenix;  class moduleaccessmanager { public:     bool getmodule(const std::string name) {         return name == "cat" || name == "dog";     } };  void globalismodule(std::string modulename, const boost::spirit::unused_type&, bool& mflag) {         moduleaccessmanager acm; /* dirty workaround example */         if(acm.getmodule(modulename))             std::cout << "[ismodule] info: found module name >"  << modulename << "<" << std::endl;         else         {             std::cout << "[ismodule] error: no module name >" << modulename << "<" << std::endl;             mflag = false; // no valid module name         } }  template <typename iterator, typename skipper> class modulecommandparser : public qi::grammar<iterator, skipper> { private:     moduleaccessmanager* m_acm;      qi::rule<iterator, skipper> start, module;  public:     std::string m_modulename;      modulecommandparser(moduleaccessmanager* acm)         : modulecommandparser::base_type(start)         , m_acm(acm)         , m_modulename("<empty>")     {         using namespace phoenix::arg_names;         module  =   qi::as_string[qi::lexeme[+(~qi::char_(' '))]]                         [qi::_pass = phoenix::bind(&moduleaccessmanager::getmodule, m_acm, qi::_1)]                     ;         start   =  module >> qi::as_string[+(~qi::char_('\n'))];     };  };   int main() {     moduleaccessmanager acm;     modulecommandparser<std::string::const_iterator, qi::space_type> commandgrammar(&acm);      std::string str;     std::string::const_iterator first;     std::string::const_iterator last;      str = "cat run";     first = str.begin();     last = str.end();     std::cout << str << std::boolalpha                << qi::phrase_parse(first, last, commandgrammar, qi::space)               << "\n";      str = "bird fly";     first = str.begin();     last = str.end();     std::cout << str << std::boolalpha                << qi::phrase_parse(first, last, commandgrammar, qi::space)               << "\n"; } 

Comments