наследование — Шаблоны выражений C ++ — Почему базовый класс?

Недавно я наткнулся на шаблоны выражений в C ++. Есть одна вещь, которую я не совсем понимаю об их реализации, и именно поэтому необходим базовый класс (из которого все другие объекты, относящиеся к выражению шаблона, выводятся способом CRTP). Простой пример, который делает сложение и скалярное умножение на векторы (объекты типа Vecбез базового класса):

#include <vector>
#include <iostream>
using namespace std;

class Vec
{
vector<double> data;
public:

template<typename E>
Vec(E expr)
{
data = vector<double>(expr.size());
for (int i = 0; i < expr.size(); i++)
data[i] = expr[i];
}
Vec(int size)
{
data = vector<double>(size);
for (int i = 0; i < size; i++)
data[i] = i;
}
double operator [] (int idx) {
return data[idx];
}

int size() { return data.size(); }

bool operator < (Vec &rhs)
{
return (*this)[0] < rhs[0];
}

bool operator > (Vec &rhs)
{
return (*this)[0] > rhs[0];
}

};

template<typename E1, typename E2>
class VecAdd
{
E1 vec_expr1;
E2 vec_expr2;

public:
VecAdd(E1 vec_expr1, E2 vec_expr2) : vec_expr1(vec_expr1), vec_expr2(vec_expr2)
{}

double operator [] (int idx) { return vec_expr1[idx] + vec_expr2[idx]; }
int size() { return vec_expr1.size(); }
};

template<typename E>
class ScalarMult
{
E vec_expr;
double scalar;

public:
ScalarMult(double scalar, E vec_expr) : scalar(scalar), vec_expr(vec_expr)
{}

double operator [] (int idx) { return scalar*vec_expr[idx]; }
int size() { return vec_expr.size(); }
};

template<typename E1, typename E2>
VecAdd<E1, E2> operator + (E1 vec_expr1, E2 vec_expr2)
{
return VecAdd<E1, E2>(vec_expr1, vec_expr2);
}

template<typename E>
ScalarMult<E> operator * (double scalar, E vec_expr)
{
return ScalarMult<E>(scalar, vec_expr);
}

int main()
{
Vec term1(5);
Vec term2(5);

Vec result = 6*(term1 + term2);
Vec result2 = 4 * (term1 + term2 + term1);

//vector<Vec> vec_vector = {result, result2};     does not compile
vector<Vec> vec_vector;

vec_vector = { result2, result };   //compiles

vec_vector.clear();
vec_vector.push_back(result);
vec_vector.push_back(result2);      //all this compiles

for (int i = 0; i < result.size(); i++)
cout << result[i] << " ";
cout << endl;

system("pause");

return 0;
}

Приведенный выше код компилируется (за исключением указанной строки) и оценивает простые выражения в основной функции без ошибок. Если выражения присваиваются объекту типа Vec и назначить их содержимое Vec объект, разрушающийся в процессе в любом случае, зачем он нужен базовому классу? (как показано в этот Статья в википедии)

РЕДАКТИРОВАТЬ:

Я знаю, что этот код немного грязный и плохой (копирование там, где это необходимо и т. Д.), Но я не планирую использовать этот конкретный код. Это просто для иллюстрации того, что шаблоны выражений работают в этом примере без базового класса CRTP — и я пытаюсь точно выяснить, почему этот базовый класс необходим.

1

Решение

Ваш

template<typename E1, typename E2>
VecAdd<E1, E2> operator + (E1 vec_expr1, E2 vec_expr2)

будет соответствовать для любой пользовательские типы, а не просто типы выражений. При создании экземпляра с не векторными типами он, скорее всего, потерпит неудачу. Это очень плохо взаимодействует с другими типами C ++, вполне возможно, включая стандартные типы библиотек, которые предоставляют свои собственные operator + и может полагаться на неточные совпадения, решающие их собственные operator + после неявных преобразований.

Изготовление operator + доступно только для VecExpression<E> избегает этой проблемы.

3

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


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