模仿简单的Boost Proto C ++表达式评估器

时间:2013-04-30 15:34:58

标签: c++ templates boost boost-proto

我希望通过使用模板参数指定do_eval转换的返回类型(迄今为止double)来构建来自here的Boost Proto“解包表达式”示例

为简洁起见,我将提供do_eval的工作,简化(仅限加)版本:

struct do_eval2 : proto::callable
{
  typedef double result_type;
  template <typename X, typename Y>
  result_type operator()(proto::tag::plus, X x, Y y) const { return x + y; }
};

然后我添加模板参数T而不是double

template <typename T>
struct do_eval2 : proto::callable
{
  typedef T result_type;
  template <typename X, typename Y>
  result_type operator()(proto::tag::plus, X x, Y y) const { return x + y; }
};

并将关联的eval结构修改为:

struct eval2
  : proto::or_<
      proto::when<proto::terminal<proto::_>, proto::_value>
    , proto::otherwise<do_eval2<double>(proto::tag_of<proto::_>(),
                                        eval2(proto::pack(proto::_))...)>
    >
{};

但是当我使用它时,如下面的代码所示,我从错误开始出错:无法将'std :: ostream {aka std :: basic_ostream}'左值绑定到'std :: basic_ostream&amp;&amp; ;'如何满足编译器?

int main(int argc, char *argv[])
{
  int one = 1, two = 2;
  cout << eval2()(phoenix::ref(one)+phoenix::ref(two)) << '\n';
  return 0;
}

2 个答案:

答案 0 :(得分:4)

正如您所见here

  

转换的形式通常为proto :: when&lt;东西,R(A0,A1,...)&gt;。问题是R是代表要调用的函数还是要构造的对象,答案决定了proto :: when&lt;&gt;评估变换。原::当&LT;&GT;使用proto :: is_callable&lt;&gt;两者之间消除歧义的特征。 Proto尽力猜测一个类型是否可以调用,但它并不总是正确的。最好知道Proto使用的规则,以便您知道何时需要更明确。

     

对于大多数类型R,proto :: is_callable检查proto :: callable的继承。但是,如果类型R是模板特化,则Proto假定即使模板继承自proto :: callable,它也不可调用。

文档提出了解决方案:您可以使用do_eval<double>包装每个proto::call的调用,或者只是在boost :: proto命名空间中专门化is_callable并忘记问题。

namespace boost { namespace proto
{
    // Tell Proto that do_eval2<> is callable
    template<typename T>
    struct is_callable<do_eval2<T> >
      : mpl::true_
    {};
}}

[编辑:]这是proto::call替代方案:

struct eval2
  : proto::or_<
      proto::when<proto::terminal<proto::_>, proto::_value>
    , proto::otherwise<
        proto::call<do_eval2<double>(proto::tag_of<proto::_>(),
                                     eval2(proto::pack(proto::_))...)>>
    >
{};

答案 1 :(得分:4)

请参阅上一个答案。我还补充说,另一种解决方案是定义do_eval2,如下所示:

template <typename T, typename D = proto::callable>
struct do_eval2 : proto::callable
{
  typedef T result_type;
  template <typename X, typename Y>
  result_type operator()(proto::tag::plus, X x, Y y) const { return x + y; }
};

请注意额外的虚拟模板参数。

编辑:此外,在目前正在开发的Proto的下一个版本中,您将不需要了解这块奥秘,并且应该只需要工作。我将在几周内在C ++上谈论它。