Шаблон наследования C ++ + CRTP - PullRequest
0 голосов
/ 20 июля 2010

я пытаюсь понять шаблон, используемый в убласе.шаблон таков:

struct vector : vector_expression<vector>

где vector_expression выглядит так:

template<class E>
class vector_expression {
...
// no constructor or E pointer/reference in class
//
const E &operator () () const {
      return *static_cast<const E*>(this);
}

полный исходный код здесь: http://www.tena -sda.org / doc / 5.2.2/boost/dd/d44/vector__expression_8hpp-source.html#l00088

мой вопрос, как работает *static_cast<const E*>(this)?это полагается на наследование?

следующий вопрос: если я получаю

template<class E>
class vector_expression2 : private vector_expression<E>
{
    //friend class ublas::vector_expression<E>; // this is the fix
    typedef vector_expression<E> base;
    const E& operator()() const { return base::operator()(); } 
 };

, я получаю ошибку компилятора относительно недоступной базы vector_expression в статическом приведении.почему это происходит?

Спасибо

Ответы [ 2 ]

2 голосов
/ 21 июля 2010

Это хитрость для ограничения шаблонов функций - для ограничения класса типов. Существует множество концепций, таких как векторное выражение, скалярное выражение, матричное выражение и т. Д. Если вы хотите написать шаблон функции, который умножает вектор на скаляр, вы можете попробовать написать

template<typename V, typename S>
some_type operator*(V v, S s);  // vector * scalar

template<typename V, typename S>
some_type operator*(S s, V v); // scalar * vector

но это не сработает, потому что оба объявления по существу эквивалентны, и никто не сказал, что V должен быть векторным выражением, а S - скалярным выражением. Итак, разработчики uBlas использовали CRTP для ограничения этих шаблонов:

template<typename V, typename S>
some_Type operator*(vector_expression<V> ve, scalar_expression<S> se);

Чтобы это работало, все скалярные выражения S должны быть производными от scalar_expression<S>, а все векторные выражения V должны быть производными от vector_expression<V>. Таким образом, этот оператор рассматривается только в том случае, если первый операнд действительно является выражением для вектора, а второй аргумент действительно является выражением для скаляра. Вы можете перегрузить этот шаблон функции вторым, который меняет оба параметра, и все в порядке.

Теперь, чтобы иметь доступ к чему-либо из V и S (производных типов), нам нужно преобразование из базового класса в производный класс. Для этого и предназначен оператор преобразования в базовом классе. Поскольку базовый класс знает производный класс (это параметр шаблона), это не проблема. Имеет смысл выбрать самый слабый оператор приведения, который позволяет при этом избегать ошибок. Это static_cast. Он может использоваться для преобразования базы * в производную * без каких-либо существенных накладных расходов.

Я не понимаю, что вы пытаетесь сделать со своим кодом

template<class E>
class vector_expression2 : private vector_expression<E>;

Если вы хотите написать собственное векторное выражение в качестве шаблона, вы должны сделать это так:

template<class E>
class my_parameterized_vector_expression
: public vector_expression<my_parameterized_vector_expression<E> >;

Я не думаю, что это работает с частным наследованием. По крайней мере, все шаблоны функций, которые принимают выражение вектора в качестве аргумента, не смогут получить доступ к оператору преобразования из базового класса, если вы здесь используете частное наследование.

1 голос
/ 21 июля 2010

Ошибка доступности, на которую вы ссылаетесь, не имеет смысла. vector_expression является struct, а вызов функции operator () является открытым. Возможно, вы пытались вызвать vector_expression2::operator ()? Это дало бы вам ошибку, потому что вы определили этот оператор как частный.

Решение вашей проблемы может быть даже проще, чем вы думаете. Если вы посмотрите исходный код ublas, то увидите, что все классы, производные vector_expression, передают себя в качестве аргумента шаблона:

template<class M>
class matrix_row: public vector_expression<matrix_row<M> > {
};

Это означает, что vector_expression может привести параметр шаблона к себе, потому что параметр шаблона происходит от vector_expression, следовательно, *static_cast<const E*>(this) работает, что является просто причудливым способом сказать *((const E*)this).

Попробуйте переписать vector_expression2 класс так:

template<class E>
class vector_expression2 : public vector_expression<vector_expression2<E>>
{
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...