c++ - 使用函数属性构造 qi::rule

标签 c++ boost-spirit boost-spirit-qi higher-order-functions expression-templates

我正在尝试创建一个返回 function<char(char const *)> 的规则通过柯里化(Currying) Phoenix 表达式构造。例如,

start = int_[_val = xxx];
rule<Iterator, function<char(char const *)> start;

应该做什么xxx以便解析字符串 "5"应该给我一个函数,给我输入的第五个字符?我尝试过类似 lambda(_a = arg1)[arg1[_a]](_1)可能有用,但我还没有找到神奇的公式。

换句话说,我希望将该属性 curry 化 arg2[arg1]关于解析的 int 的值

非常感谢您的任何建议。请注意,我使用的是 VC2008,因此 C++11 lambda 不可用。

迈克

最佳答案

修复规则声明后:

typedef boost::function<char(char const*)> Func;
qi::rule<Iterator, Func()> start;

它有效: Live On Coliru (c++03)。

更新:

为什么我最终会得到如此复杂的装置?

qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1)

嗯。让我告诉您使用惰性求值来复杂化函数组合的乐趣(在 C++ 模板元编程中,引用/值语义具有这些令人惊讶的功能):不要执行以下操作:

qi::_val = px::lambda(_a = qi::_1) [arg1[_a]] // UB!!! DON'T DO THIS

根据编译器、优化级别,这可能*看起来有效。但它调用了未定义行为[1]。问题在于 qi::_1 将保留为 qi::int_ 解析器表达式公开的属性的引用。然而,在解析器上下文的生命周期结束后,该引用是一个悬空引用。

因此,通过无效引用间接评估仿函数。为了避免这种情况,你应该说( Live On Coliru ):

qi::_val = px::lambda(_a = px::val(qi::_1)) [arg1[_a]]

甚至(如果你喜欢晦涩的代码):

qi::_val = px::lambda(_a = +qi::_1) [arg1[_a]]

或者,您知道,您可以坚持使用绑定(bind)的嵌套 lambda,因为绑定(bind)默认qi::_1 的值语义(除非您使用 phx::cref/phx::ref 包装器)。

我希望上述分析能够让我明白我之前在评论中提出的观点:

Note that I wouldn't recommend this code style. Higher-order programming with Phoenix is tricky enough without composing them from within lazy actors in some embedded expression-template DSL: qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1). 'Nuff said?


#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/function.hpp>

namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;

typedef boost::function<char(char const*)> Func;

int main()
{
    typedef std::string::const_iterator Iterator;
    using namespace boost::phoenix::arg_names;

    qi::rule<Iterator, Func()> start;

    start = qi::int_ 
            [ qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1) ];
    // or:  [ qi::_val = px::lambda(_a = px::val(qi::_1))[arg1[_a]] ];

    static char const* inputs[] = { "0", "1", "2", "3", "4", 0 };

    for (char const* const* it = inputs; *it; ++it)
    {
        std::string const input(*it);
        Iterator f(input.begin()), l(input.end());

        Func function;
        bool ok = qi::parse(f, l, start, function);

        if (ok)
            std::cout << "Parse resulted in function() -> character " 
               << function("Hello") << "; " 
               << function("World") << "\n";
        else
            std::cout << "Parse failed\n";

        if (f != l)
            std::cout << "Remaining unparsed: '" << std::string(f, l) << "'\n";
    }
}

打印

Parse resulted in function() -> character H; W
Parse resulted in function() -> character e; o
Parse resulted in function() -> character l; r
Parse resulted in function() -> character l; l
Parse resulted in function() -> character o; d

[1](MSVC2013 似乎崩溃,gcc 可能在 -O3 中工作,但在 -O0 等中出现段错误)

关于c++ - 使用函数属性构造 qi::rule,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25987763/

相关文章:

c++ - 在 C++ 下调用 asm sqrtsd

C++ 扑克 : skipping over If statements, 并忽略值

c++ - Boost spirit 计算器示例运行

c++ - 振奋精神 : how to parse until we have "->"

c++ - 使用 Boost::Spirit 解析异构数据

c++ - Boost Spirit Visual C++ 编译器错误,适用于 GCC

c++ - 更正友元定义以授予 std::map 对私有(private)默认构造函数的访问权限

c++ - 处理从 QProcess 运行的程序中的段错误

C++解析比特流

c++ - 语法平衡问题