C++ Boost spirit:从成员函数中使解析器无效

C++ Boost spirit:从成员函数中使解析器无效,c++,semantics,boost-spirit-qi,boost-phoenix,C++,Semantics,Boost Spirit Qi,Boost Phoenix,本文()解释了如何使用签名使普通函数中的匹配无效 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 &

本文()解释了如何使用签名使普通函数中的匹配无效

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);
}
使用全局函数很好,但这不是我的选择,因为我需要访问特定于解析器的m_acm对象

如何将成员函数绑定到语义操作,同时使该成员函数的匹配无效(使用上述3参数函数签名)?

有两种方法:

  • 您可以使用Phoenix actors分配给
    qi::\u val
  • 您可以在“原始”语义动作函数中指定第三个参数(
    bool&
例如:

  • (使用
    \u val
语义动作功能的剖析(第三个参数):


在您的例子中,您有一个成员函数,其签名大致为“原始语义动作函数”。当然,您必须为
this
参数绑定(因为它是一个非静态成员函数)

请注意,在这种特殊情况下,
phoenix::bind
不是正确的绑定,因为phoenix演员将被视为“煮熟”(而非原始)语义动作,它们将在Spirit上下文中执行

你也可以

  • 使用
    boost::bind
    (甚至
    std::bind
    )绑定到保留成员函数的arity(!)的函数中:

    [boost::bind(&moduleCommandParser::isModule, this, ::_1, ::_2, ::_3)]
    
    这是有效的:

  • 而是使用一个“煮熟的”语义动作,直接分配给
    \u pass
    上下文占位符:

    [qi::_pass = phoenix::bind(&moduleAccessManager::getModule, m_acm, qi::_1)]
    
    这同样有效:

  • 后一个示例,供将来参考:

    #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";
    }
    
    #定义提升(精神)使用(凤凰)
    #包括
    #包括
    #包括
    #包括
    名称空间qi=boost::spirit::qi;
    名称空间phoenix=boost::phoenix;
    类模块访问管理器{
    公众:
    bool getModule(const std::string name){
    返回名称==“猫”| |名称==“狗”;
    }
    };
    void globalIsModule(std::string moduleName,const boost::spirit::unused_type&,bool&mFlag)
    {
    moduleAccessManager acm;/*此示例的脏解决方法*/
    if(acm.getModule(moduleName))
    
    std::你是否应该包括
    boost/spirit/include
    文件夹中的include,而不是当前正在阅读代码示例的主文件夹。显然,我已经告诉了你一些你已经知道的事情。:)仍然有人在回答问题。现在将查看修复示例代码在我的答案中添加了一些带有示例的方法现在。
    #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";
    }