::提振精神,通过语义动作在继承属性 [英] Boost::spirit passing semantic actions in inherited attributes

查看:165
本文介绍了::提振精神,通过语义动作在继承属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想通过语义动作的语法继承的说法。

在语法下面的非常简单的例子分析两个数字,我传递的语义动作(在C ++拉姆达的一种形式)到它,我想在第一个数字解析被称为这个动作。然而,它不叫,但忽略掉,我想知道为什么会这样,什么是做这种事情的正确方法。

 的#include<&iostream的GT;
#包括LT&;升压/精神/有/ qi.hpp>使用命名空间std;
使用名字空间boost;命名空间补气=精神::补气;
命名空间PHX =凤凰;模板< typename的迭代器,typename的作用>
结构two_numbers:补气::语法<迭代器,无效(动作常量和放大器;)>
{
  two_numbers():two_numbers :: base_type(开始)
  {
    使用命名空间补气;
    开始= int_ [_r1>> ''>> int_;
  }
  齐::规则<迭代器,无效(动作常量和放大器;)>开始;
};诠释的main()
{
  字符串输入{42 21};
  汽车第一=的std ::开始(输入),最后=的std ::端(输入);  静态常量自动my_action = [](自动&安培;&安培; P){
    COUT<< 生命的意义是<< P<< \\ n;
  };  静态常量two_numbers< decltype(第一),decltype(my_action)GT;磷;  如果(气::解析(第一个,最后,P(PHX :: REF(my_action))))
    COUT<< 解析OK \\ N的;
}

预期的输出是:

 生命的意义是42
解析确定

和真正的输出是:

 解析确定


解决方案

第一,立即,响应:


  

我试图通过语义动作的语法继承的说法。


即时创伤性休克。你......你......什么?!

C ++不适合高阶编程非常好,绝对不是静态多态性基于前pression模板。事实上,它是,但在我的previous答案,我在一个名为对象存储前pression模板时已经告诫UB(≅变量)。

围绕它当时是 UB 你发现。这是幸运的,在我看来。

最近,我已经遇到了类似的有关目标的另一个问题是:

要特别注意评论跟帖。我不认为这是一个理智的道路,至少直到升压的Mpl已具有完全C ++ 11善做(的升压花,也许?)和原-0X 被释放。

届时,精神X3可能是成熟,我们只是留下了升压凤凰的差距。我不知道这是否是对任何人的议事日程。

在短期:我们会停留在这个半途而废的土地上,我们可以有好东西,但也有一些pretty约束限制。也许我们应该避免让冲昏头脑,我们很突然能够在C ++编写的Haskell pretending。

另外有关:有一个提案( N4221,PDF )在C ++参考广义寿命延长。它配备了说,是默默的在UB当前的C升压范围适配器++的简单应用一些很好的例子。例如。从§2.3环球观察:

 的std ::矢量<&INT GT; VEC;
对于(INT VAL:VEC |的boost ::适配器::逆转
                   |提高::适配器:: uniqued)
{
       //错误:结果(VEC | ::逆转的boost ::适配器)死亡。
}


解决方案

这是说,自从继承了论证会是一个仿函数(而不是一个懒惰的演员),你需要绑定:

 开始= int_ [PHX ::绑定(PHX :: CREF(_r1),齐:: _ 1)]>> ''>> int_;

这不工作: 住在Coliru

然而,我不建议这样做

I'm trying to pass semantic action in a grammar's inherited argument.

In the very basic example below the grammar parses two numbers and I pass semantic action (in a form of c++ lambda) into it and I'd like this action to be called on parsing of the first number. However it does not called but silently ignored and I'd like to know why is it so and what is the proper way to do such things.

#include <iostream>
#include <boost/spirit/include/qi.hpp>

using namespace std;
using namespace boost;

namespace qi = spirit::qi;
namespace phx = phoenix;

template <typename Iterator, typename Action>
struct two_numbers : qi::grammar<Iterator, void (Action const&)>
{
  two_numbers() : two_numbers::base_type(start)
  {
    using namespace qi;
    start = int_ [ _r1 ] >> ' ' >> int_;
  }
  qi::rule<Iterator, void (Action const&)> start;
};

int main ()
{
  string input { "42 21" };
  auto first=std::begin (input), last=std::end(input);

  static const auto my_action = [] (auto&& p) {
    cout << "the meaning of life is " << p << "\n";
  };

  static const two_numbers <decltype(first), decltype (my_action)> p;

  if (qi::parse (first, last, p(phx::ref(my_action))))
    cout << "parse ok\n";
}

The expected output is:

the meaning of life is 42
parse ok

And the real output is:

parse ok

解决方案

First, immediate, response:

"I'm trying to pass semantic action in a grammar's inherited argument."

instant traumatic shock. You... you... what?!

C++ is not very good for higher order programming, certainly not with static polymorphism based on expression templates. In fact it is, but in my previous answer I already cautioned against UB when storing expression templates in named objects (≅ variables).

That time around it was UB that you spotted. That's lucky, in my opinion.

Recently, I've already encountered another question about similar goals:

Pay special attention to the comment thread. I don't think this is a sane path, at least not until Boost Mpl has been done with full C++11 goodness (Boost Hana, perhaps?) and Proto-0x is released.

By then, Spirit X3 is probably mature, and we're just left with the gap of Boost Phoenix. I'm not sure whether that's on anyones agenda.

In short: we'll be stuck in this "halfway" land where we can have nice things, but with some pretty constrained restrictions. We should probably avoid getting carried away and pretending we're suddenly capable of writing Haskell in C++.

Also relevant: There's a proposal (N4221, pdf) for Generalized Lifetime Extension of References in C++. It comes with some good examples of simple applications of say Boost Range adaptors that are silently UB in current C++. E.g. from §2.3 Universal observation:

std::vector<int> vec;
for (int val : vec | boost::adaptors::reversed
                   | boost::adaptors::uniqued) 
{
       // Error: result of (vec | boost::adaptors::reversed) died.
}


Solution

That said, since the inherited argument would be a functor (not a lazy actor), you need to bind it:

    start = int_ [ phx::bind(phx::cref(_r1), qi::_1) ] >> ' ' >> int_;

That does work: Live On Coliru

However, I don't recommend this

这篇关于::提振精神,通过语义动作在继承属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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