Boost :: spirit在继承的属性中传递语义动作

时间:2014-10-16 22:04:11

标签: c++ parsing boost grammar boost-spirit

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

在下面的基本示例中,语法解析了两个数字,并将语义动作(以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 ok\n";
}

预期输出为:

the meaning of life is 42
parse ok

实际输出是:

parse ok

1 个答案:

答案 0 :(得分:4)

首先,立即,回应:

  

“我正试图在语法的继承论证中传递语义动作。”

瞬间创伤性休克。你......你......什么?!

C ++对高阶编程不是很好,当然也不是基于表达式模板的静态多态。实际上它是,但在我之前的回答中,我已经在命名对象(≅变量)中存储表达式模板时告诫UB。

你发现的时间是UB。在我看来,这很幸运。

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

特别注意评论主题。我不认为这是一条理智的道路,至少在Boost Mpl完成完整的C ++ 11优点(Boost Hana,或许?)并且Proto-0x被释放之前不会这样。

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

简而言之:我们将被困在这个“中途”的土地上,在那里我们可以拥有美好的东西,但有一些非常有限的限制。我们应该避免被带走并假装我们突然能够用C ++编写Haskell。

同样相关:有一个提议(N4221, pdf)用于C ++中的广义生命周期扩展引用。它附带了一些很好的例子,说明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.
}

解决方案

那就是说,因为继承的参数是一个仿函数(不是一个懒惰的actor),你需要绑定它:

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

确实有效: Live On Coliru

但是,我不推荐这个