使用函数属性构造qi :: rule

时间:2014-09-23 05:51:34

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

我试图创建一个规则,返回通过curry Phoenix表达式构造的function<char(char const *)>。如,

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

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

换句话说,我喜欢在解析的int的值上调用arg2[arg1]的属性

非常感谢任何建议。请注意,我在VC2008上,所以C ++ 11 lambdas不可用。

麦克

1 个答案:

答案 0 :(得分: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

根据编译器的优化级别,这可能会 *显示。但它正在调用未定义的行为 [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,因为绑定默认qi::_1的值语义(除非您使用phx::cref / { {1}}封套)。

我希望上面的分析能够让我回想起我之前在评论中提出的观点:

  

请注意,我不推荐这种代码风格。使用Phoenix的高阶编程非常棘手,而不是在某些嵌入式表达式模板DSL中的惰性演员中编写它们:phx::ref 'Nuff说


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

[1] (MSVC2013似乎崩溃了,gcc似乎可以在-O3中运行,但在-O0中也可以使用段错误。)