2

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

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

应该xxx是什么让解析字符串"5"应该给我一个函数,给我输入的第五个字符?我已经尝试过lambda(_a = arg1)[arg1[_a]](_1)可能有用的方法,但我无法找到神奇的公式。

换句话说,我希望属性对arg2[arg1]解析的 int 的值进行curry

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

麦克风

4

1 回答 1

2

修复该规则声明后:

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

根据编译器、优化级别,这可能*似乎有效。但它正在调用 Undefined Behavior [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]]

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

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

请注意,我不推荐这种代码风格。使用 Phoenix 进行高阶编程已经足够棘手,无需在某些嵌入式表达式模板 DSL 中从惰性 actor 中组合它们:qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1). '纳夫说


#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 等中出现段错误)

于 2014-09-23T08:44:26.960 回答