在Boost.proto中使用派生类作为终端

时间:2016-04-13 20:34:56

标签: c++ c++11 boost boost-proto

假设您想要使用Boost.proto实现一个简单的EDSL(嵌入式域特定语言),并满足以下要求:

  • 自定义类'Vector'作为终端
  • 从'Vector'派生的类也是工作终端,例如Vector10

阅读Boost.proto的手册,似乎与此最接近的相关示例是“Vector:Adapting a-Proto Terminal Type”示例。

我对该示例所做的修改:

  • 添加了'矢量'类
  • Protofied Vector代替std :: vector

这里是代码(编译):

#include <vector>
#include <iostream>
#include <stdexcept>
#include <boost/mpl/bool.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/debug.hpp>
#include <boost/proto/context.hpp>
#include <boost/utility/enable_if.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
using proto::_;

class Vector;

template<typename Expr>
struct VectorExpr;

struct VectorSubscriptCtx
{
    VectorSubscriptCtx(std::size_t i)
      : i_(i)
    {}

    template<typename Expr, typename EnableIf = void>
    struct eval
      : proto::default_eval<Expr, VectorSubscriptCtx const>
    {};

    template<typename Expr>
    struct eval<
        Expr
      , typename boost::enable_if<
            proto::matches<Expr, proto::terminal< Vector > >
        >::type
    >
    {
        typedef typename proto::result_of::value<Expr>::type::value_type result_type;

        result_type operator ()(Expr &expr, VectorSubscriptCtx const &ctx) const
        {
            return proto::value(expr)[ctx.i_];
        }
    };

    std::size_t i_;
};




struct VectorGrammar : proto::or_<
    proto::terminal< proto::_ >,
    proto::plus< VectorGrammar, VectorGrammar>,
    proto::minus< VectorGrammar, VectorGrammar>
> {};

struct VectorDomain
  : proto::domain<proto::generator<VectorExpr>, VectorGrammar>
{};



template<typename Expr>
struct VectorExpr
  : proto::extends<Expr, VectorExpr<Expr>, VectorDomain>
{
    explicit VectorExpr(Expr const &expr)
      : proto::extends<Expr, VectorExpr<Expr>, VectorDomain>(expr)
    {}

    typename proto::result_of::eval<Expr const, VectorSubscriptCtx const>::type
    operator []( std::size_t i ) const
    {
        VectorSubscriptCtx const ctx(i);
        return proto::eval(*this, ctx);
    }
};




class Vector {
private:
  int sz;
  double* data;

public:
  typedef double value_type;

  explicit Vector(int sz_ = 1, double iniVal = 0.0) :
    sz( sz_), data( new double[sz] ) {
    for (int i = 0; i < sz; i++) data[i] = iniVal;        
  }
  Vector(const Vector& vec) :
    sz( vec.sz), data( new double[sz] ) {
    for (int i = 0; i < sz; i++) data[i] = vec.data[i];
  }

  size_t size() const {return sz; }

  ~Vector() {
    delete [] data;
  }

  double& operator[](int i) { return data[i]; }
  const double& operator[](int i) const { return data[i]; }
};



class Vector10: public Vector 
{
public:
  Vector10() : Vector(10,0.0) {}
};




template<typename T>
struct IsVector
  : mpl::false_
{};


template<>
struct IsVector< Vector >
  : mpl::true_
{};



namespace VectorOps
{
    BOOST_PROTO_DEFINE_OPERATORS(IsVector, VectorDomain)

    typedef VectorSubscriptCtx const CVectorSubscriptCtx;

    template<typename Expr>
    Vector &assign(Vector &arr, Expr const &expr)
    {
        for(std::size_t i = 0; i < arr.size(); ++i)
        {
            arr[i] = proto::as_expr<VectorDomain>(expr)[i];
        }
        return arr;
    }
}



int main()
{
    using namespace VectorOps;

    Vector a,b,c,d;

    VectorOps::assign(d, a + b );
}

已经定义了派生类Vector10。现在 - 使用那个而不是Vector

int main()
{
    using namespace VectorOps;

    Vector10 a,b,c,d;

    VectorOps::assign(d, a + b );
}

导致编译错误

vector_proto_baseclass.cc:168:28: error: no match for ‘operator+’ (operand types are ‘Vector10’ and ‘Vector10’)

我相信Vector的运算符在名称空间VectorOps中正确定义,但ADL不会为派生类启动。

0 个答案:

没有答案