用函数属性构造qi :: rule [英] Constructing a qi::rule with a function attribute

查看:102
本文介绍了用函数属性构造qi :: rule的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个规则,该规则返回通过引用Phoenix表达式构造的function<char(char const *)>.例如,

I'm trying to create a rule that returns a function<char(char const *)> constructed by currying a Phoenix expression. E.g.,

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

xxx应该是什么,以便解析字符串"5"应该给我一个函数,该函数给我输入的第五个字符?我已经尝试过像lambda(_a = arg1)[arg1[_a]](_1)这样的方法可能会起作用,但是我无法触及魔术公式.

What should xxx be so that parsing the string "5" should give me a function that gives me the fifth character of its input? I've tried things like lambda(_a = arg1)[arg1[_a]](_1) might work, but I've not been able to hit on the magic formula.

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

In other words, I'd like the attribute to curry arg2[arg1] on the value of the parsed int

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

Very grateful for any suggestions. Note that I'm on VC2008, so C++11 lambdas not available.

迈克

推荐答案

修复该规则声明后:

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

它起作用了: 在Coliru上直播 (c + +03).

it worked: Live On Coliru (c++03).

更新:

为什么我会遇到这么复杂的事情?

Why did I end up with such a complex contraption?

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

好吧.让我告诉您有关通过懒惰的评估使功能组合复杂化的乐趣(在C ++模板元编程中,这些引用/值语义令人惊讶):请勿执行以下操作:

Well. Let me tell you about the joy of complexing functional composition with lazy evaluation (in C++ template meta-programming that has these surprises with reference/value semantics): Don't do the following:

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

取决于编译器的优化级别,这可能 *似乎起作用.但是它正在调用未定义行为 [1] .问题在于,qi::_1将作为对qi::int_解析器表达式公开的属性的引用保留.但是,在解析器上下文的生存期结束后,该引用是一个悬空引用.

Depending on the compiler, optimization level, this might *appear to work. But it's invoking Undefined Behaviour [1]. The problem is that qi::_1 will be kept as a reference to the attribute exposed by qi::int_ parser expression. However, this reference, after the lifetime of the parser context has ended, is a dangling reference.

因此,通过无效引用对函子进行间接求值.为避免这种情况,您应该说( 在Coliru上直播 ):

So evaluating the functor indirects through an invalid reference. To avoid this you should say (Live On Coliru):

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

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

or even (if you like obscure code):

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

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

Or, you know, you can stick with the bound nested lambda, since the bind defaults to value-semantics for qi::_1 (unless you used the phx::cref/phx::ref wrappers).

我希望以上分析能使我早些时候在评论中所指出的观点成为现实.

I hope the above analysis drives home the point I made in the comments earlier:

请注意,我不会推荐这种代码样式.使用Phoenix进行高阶编程非常棘手,而无需在某些嵌入式表达模板DSL:qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1)中从懒惰的参与者中编写它们. 'Nuff说 ?

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等中工作)


[1] (MSVC2013 appeared to crash, gcc may appear to work in -O3, but segfaults in -O0 etc.)

这篇关于用函数属性构造qi :: rule的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆