1

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

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

阅读 Boost.proto 的手册,似乎与此最相关的示例是“向量:调整非原型终端类型”示例。

我对该示例所做的修改:

  • 添加了“矢量”类
  • 原型向量而不是 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 不会为派生类启动。

4

0 回答 0