【问题标题】:Templating a Simple Boost Proto C++ Expression Evaluator模板化一个简单的 Boost Proto C++ 表达式求值器
【发布时间】:2013-04-30 15:34:58
【问题描述】:

我想在 here 的 Boost Proto“解包表达式”示例的基础上进行构建,方法是使用模板参数指定 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; }
};

并将关联的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::_))...)>
    >
{};

但是当我使用它时,如下面的代码所示,我得到错误以 error: cannot bind 'std::ostream {aka std::basic_ostream}' lvalue to 'std::basic_ostream&&' 怎样才能让编译器满意?

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

【问题讨论】:

    标签: c++ templates boost boost-proto


    【解决方案1】:

    如你所见here:

    转换通常采用 proto::when 的形式。问题是 R 是表示要调用的函数还是要构造的对象,答案决定了 proto::when 如何评估转换。 proto::when 使用 proto::is_callable 特征来消除两者之间的歧义。 Proto 会尽力猜测一个类型是否是可调用的,但它并不总是正确的。最好了解 Proto 使用的规则,以便您知道何时需要更明确。

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

    文档提出了解决方案:您可以使用 proto::call 包装每次调用 do_eval&lt;double&gt;,或者您只需在 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::_))...)>>
        >
    {};
    

    【讨论】:

      【解决方案2】:

      查看上一个答案。我还要补充一点,另一种解决方案是像这样定义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 上讨论它。

      【讨论】:

      • +1 以获得答案,很高兴看到更多 Boost 作者在此站点上变得活跃!
      • 3 个答案:你们在宠我 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 2015-08-02
      相关资源
      最近更新 更多