Boost::精神传递继承属性中的语义动作



我试图在语法的继承参数中传递语义操作。

在下面这个非常基本的例子中,语法解析两个数字,我将语义动作(以c++lambda的形式)传递给它,我希望在解析第一个数字时调用这个动作。然而,它并没有被召唤,而是被默默地忽视了,我想知道为什么会这样,做这些事情的正确方法是什么。

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

预期输出为:

the meaning of life is 42
parse ok

实际输出是:

parse ok

首先,立即,响应:

"我试图在语法的继承论点中传递语义动作。"

瞬间创伤性休克。你你什么

C++不太适合高阶编程,当然也不适合基于表达式模板的静态多态性。事实上是这样的,但在我之前的回答中,我已经警告过在命名对象中存储表达式模板时不要使用UB。

那一次你发现的是UB。在我看来,这是幸运的。

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

  • 构造具有函数属性的qi::规则

请特别注意评论线程。我不认为这是一条合理的道路,至少在Boost Mpl完成了完整的C++11(也许是Boost Hana?)并发布Proto-0x之前。

到那时,Spirit X3可能已经成熟,我们只剩下Boost Phoenix的差距。我不确定这是否在任何人的议程上。

简言之:我们将被困在这片"中途"的土地上,在那里我们可以有美好的东西,但有一些非常有限的限制。我们可能应该避免得意忘形,假装自己突然有能力用C++编写Haskell。

同样相关的是:有一个关于C++中引用的广义寿命扩展的建议(N4221,pdf)。它附带了一些简单应用程序的好例子,比如Boost Range适配器,它们在当前C++中是静默UB。例如,来自§2.3的普遍观察:

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

解决方案

也就是说,由于继承的参数将是一个函子(而不是一个懒惰的参与者),您需要绑定它:

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

这确实有效:在Coliru上直播

但是,我不建议使用此

最新更新