【问题标题】:Boost spirit: Invalidate parser from member function提升精神:使成员函数中的解析器无效
【发布时间】:2015-10-07 01:19:17
【问题描述】:

这篇文章 (boost spirit semantic action parameters) 解释了如何使用签名使普通函数中的匹配无效

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 参数函数签名)?

【问题讨论】:

  • 您应该包含来自boost/spirit/include 文件夹而不是主文件夹的包含

标签: c++ semantics boost-spirit-qi boost-phoenix


【解决方案1】:

有两种方式:

  • 您可以使用 Phoenix 演员分配给 qi::_val
  • 您可以在“原始”语义操作函数内分配给第三个参数 (bool&amp;)

这里有一个例子:

语义动作函数的剖析(带有第三个参数):


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

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

你也可以

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

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

【讨论】:

  • 目前正在阅读您的代码示例。显然我已经告诉了你一些你已经知道的事情。 :) 仍然有人按照要求回答问题。现在将研究修复示例代码
  • 现在在我的答案中添加了一些带有示例的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-08
相关资源
最近更新 更多