Использование производного класса в качестве терминалов в Boost.proto

Предположим, вы хотите реализовать простой EDSL (Embedded Domain Specific Language) с Boost.proto со следующими требованиями:

  • Пользовательский класс «Вектор» в качестве терминала
  • Классы, производные от Vector, также являются рабочими терминалами, например, Vector10

Читая руководство по Boost.proto, кажется, что наиболее близким примером этого является пример «Вектор: Адаптация непротопного типа терминала».

Модификации, которые я сделал в этом примере:

  • Добавлен класс «Вектор»
  • 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’)

Я считаю, что операторы для вектора правильно определены в пространстве имен VectorOps, но ADL не включается для производного класса.

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector