2015-07-17 4 views
2

эта статья (boost spirit semantic action parameters) объясняет, как аннулирует соответствие с обычной функции с подписьюПовысьте дух: Invalidate анализатор от функции члена

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

Я хотел бы сделать недействительным матч из функции члена грамматики :

#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 for this example */ 
     if(acm.getModule(moduleName)) 
      std::cout << "[isModule] Info: Found module with name >" << moduleName << "<" << std::endl; 
     else 
     { 
      std::cout << "[isModule] Error: No module with 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] // This 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 a module with moduleName exists 
     if(m_acm->getModule(moduleName)) 
      std::cout << "[isModule] Info: Found module with name >" << moduleName << "<" << std::endl; 
     else 
     { 
      std::cout << "[isModule] Error: No module with 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); 
} 

Код на Coliru: http://coliru.stacked-crooked.com/a/4319b38a6d36c362

важной частью эти две линии:

  [&globalIsModule] // This works fine 
//   [phoenix::bind(&moduleCommandParser::isModule, this)] // Compile error 

Использование глобальной функции работает нормально, но это не вариант для меня, потому что мне нужен доступ к объекту m_acm, который специфичен для синтаксического анализатора.

Как я могу привязать функцию-член к семантическому действию и в то же время иметь возможность аннулировать соответствие из этой функции-члена (используя упомянутую выше 3-значную функцию функции аргумента)?

+2

Вы должны включать в себя включают от 'подталкивания/дух/include' папки вместо домашней папки – sehe

ответ

2

Есть два способа:

  • вы можете присвоить qi::_val с помощью актеров Phoenix
  • вы можете назначить третьего параметра (bool&) внутри "сырой" семантической функции действия

Примером может служить пример:

анатомия семантической функции действия (с третьим аргументом):


В вашем случае у вас есть функция-член с грубо обозначение «сырой семантической действия». Конечно, вам придется привязываться к параметру this (потому что это нестатическая функция-член).

Обратите внимание, что в данном конкретном случае phoenix::bind не является подходящим для использования, поскольку актеры Феникса будут считаться «приготовленными» (не сырыми) семантическими действиями, и они будут исполняться в контексте Духа.

Вы можете либо

  1. использование boost::bind (или даже std::bind), чтобы связать в функцию, которая сохраняет Арность (!) Функции члена:

    [boost::bind(&moduleCommandParser::isModule, this, ::_1, ::_2, ::_3)] 
    

    Это работает: Live On Coliru

  2. вместо этого использовать "приготовленную" семантическое действие, непосредственно назначая к _pass контекста заполнителем:

    [qi::_pass = phoenix::bind(&moduleAccessManager::getModule, m_acm, qi::_1)] 
    

    это работает также: Live On Coliru

Последнего пример, для дальнейшего использования:

#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 for this example */ 
     if(acm.getModule(moduleName)) 
      std::cout << "[isModule] Info: Found module with name >" << moduleName << "<" << std::endl; 
     else 
     { 
      std::cout << "[isModule] Error: No module with 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"; 
} 
+0

В настоящее время читает ваш образец кода. Видимо, я рассказал вам кое-что, что вы уже знали. :) Тем не менее они отвечали на вопрос, как его задавали. Посмотрите на исправление кода образца сейчас. – sehe

+0

Добавлены некоторые подходы с образцами к моему ответу сейчас. – sehe