模板化一个简单的Boost Proto C++表达式计算器

Templating a Simple Boost Proto C++ Expression Evaluator

本文关键字:Boost Proto C++ 计算器 表达式 简单 一个      更新时间:2023-10-16

我想在Boost Proto"Unpacking Expressions"示例的基础上,使用模板参数来指定do_eval转换(迄今为止为double(的返回类型。

为了简洁起见,我将介绍一个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; }
};

并将关联的CCD_ 6结构修改为:

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_stream}"lvalue绑定到"std::basic_stream&amp;'如何满足编译器的要求?

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

如您所见:

变换通常具有proto::when<Something,R(A0,A1,…(>。问题是R是表示要调用的函数还是表示要构造的对象,答案决定了proto::when<gt;评估变换。proto::when<gt;使用proto::is_callable<gt;消除两者之间歧义的特点。Proto尽力猜测一个类型是否可调用,但它并不总是正确的。最好知道Proto使用的规则,这样你就知道什么时候需要更明确。

对于大多数类型R,proto::is_callable检查proto::callable的继承。但是,如果类型R是模板专用化,Proto会认为它是不可调用的,即使该模板继承自Proto::callable。

该文档提出了解决方案:您可以用proto::call包装do_eval<double>的每次调用,也可以简单地将is_callable专门化到boost::proto命名空间中,然后忘记这个问题。

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::_))...)>>
    >
{};

请参阅前面的答案。我还想补充一点,另一个解决方案是这样定义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++Now上讨论这个问题。