Могу ли я дать различные варианты поведения для типов меток boost :: proto ::?

Я пытаюсь использовать boost proto для ленивой оценки выражений. Я хочу, чтобы теги, такие как +, -, function и т. Д., Имели различное поведение.

function(
terminal(8functionILi2EE)
, plus(
multiplies(
terminal(6tensorILi0EE)
, terminal(6tensorILi1EE)
)
, multiplies(
terminal(6tensorILi2EE)
, terminal(6tensorILi3EE)
)
)
)

Для дерева, подобного выше, я хочу иметь возможность указать, как должен вести себя каждый из узлов дерева.

Например,

struct context : proto::callable_context< context const >
{

// Values to replace the tensors
std::vector<double> args;

// Define the result type of the zero.
// (This makes the zero_context "callable".)
typedef double result_type;

// Handle the tensors:
template<int I>
double operator()(proto::tag::terminal, tensor<I>) const
{
std::cout << this->args[I] << std::endl;
return this->args[I];
}

template<int I>
void operator()(proto::tag::plus) const
{
std::cout << " + " << std::endl;
}

};

Когда я делаю

double result = (_tensorA + _tensorB)(10, 20);

Я ожидаю, что мой результат будет

10
+
20

Но это просто

10
20

Любая помощь будет высоко ценится! 🙂

2

Решение

template<int I>
void operator()(proto::tag::plus) const
{
std::cout << " + " << std::endl;
}

Аргумент шаблона I не выводится, поэтому перегрузка никогда не будет применима. Удалите аргумент шаблона:

void operator()(proto::tag::plus) const
{
std::cout << " + " << std::endl;
}

ОДНАКО То, что вы действительно хотите, это перехватить бинарный оператор. Что ж. Обратите внимание, это двоичный. Итак, у него есть два аргумента:

template<size_t I, size_t J>
void operator()(proto::tag::plus, proto::literal<tensor<I>>&, proto::literal<tensor<J>>&) const {
std::cout << " + " << std::endl;
}

Жить на Колиру

Однако это блокирует дальнейшую оценку дерева выражений. Не то, что вы хотели, верно. Итак, давайте сделаем упрощенную повторную реализацию:

template<size_t I, size_t J>
double operator()(proto::tag::plus, proto::literal<tensor<I>>& a, proto::literal<tensor<J>>& b) const {
auto va = (*this)(proto::tag::terminal{}, a.get());
std::cout << " + " << std::endl;
auto vb = (*this)(proto::tag::terminal{}, b.get());
return va + vb;
}

Жить на Колиру

Дженерик, пожалуйста

Тем не менее, кое-что говорит мне, что вы хотели родовые выражения. Так t1 + (t2 + t3) тоже должно работать, но (t2 + t3) не буквально …

Давайте упростим делегирование:

template<typename A, typename B>
double operator()(proto::tag::plus, A& a, A& b) const {
auto va = proto::eval(a, *this);
std::cout << " + " << std::endl;
auto vb = proto::eval(b, *this);
return va + vb;
}

Полный образец

Жить на Колиру

#include <boost/proto/proto.hpp>
#include <vector>

namespace proto = boost::proto;

template <size_t N> struct tensor { };
template <size_t N, size_t M> tensor<N+M> operator+(tensor<N>, tensor<M>) { return {}; }

struct context : proto::callable_context< context const >
{
using base_type = proto::callable_context<context const>;

// Values to replace the tensors
std::vector<double> args { 0, 111, 222, 333 };

// Define the result type of the zero.
// (This makes the zero_context "callable".)
typedef double result_type;

// Handle the tensors:
template<size_t I>
double operator()(proto::tag::terminal, tensor<I>) const
{
std::cout << this->args[I] << std::endl;
return this->args[I];
}

template<typename A, typename B>
double operator()(proto::tag::plus, A& a, B& b) const {
auto va = proto::eval(a, *this);
std::cout << " + " << std::endl;
auto vb = proto::eval(b, *this);
return va + vb;
}
};

int main() {
proto::literal<tensor<1> > t1;
proto::literal<tensor<2> > t2;
proto::literal<tensor<3> > t3;
auto r = proto::eval(t1 + (t2 + t3), context());
std::cout << "eval(t1 + (t2 + t3)) = " << r << "\n";
}

Печать

111
+
222
+
333
eval(t1 + (t2 + t3)) = 666
1

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

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

По вопросам рекламы [email protected]