Tutorial :C++ inheritance pattern + CRTP



Question:

am trying to understand pattern used in ublas. pattern is such:

struct vector : vector_expression<vector>  

where vector_expression is like this:

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

complete source code is here: http://www.tena-sda.org/doc/5.2.2/boost/dd/d44/vector__expression_8hpp-source.html#l00088

my question is, how does *static_cast<const E*>(this) work? does it rely on inheritance?

next question: if I derive

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()(); }    };  

i get compiler error regarding inaccessible vector_expression base in static cast. why does it happen?

Thank you


Solution:1

This is a trick to constrain function templates -- to restrict the class of types. There are lots of concepts like vector expression, scalar expression, matrix expression etc. If you want to write a function template that multiplies a vector with a scalar you could try to write

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  

but this is not going to work because both declarations are essentially equivalent and nobody said that V is supposed to be a vector expression and S is supposed to be a scalar expression. So, what the uBlas developers did is to use the CRTP to constrain these templates:

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

To make this work all scalar expressions S have to derive from scalar_expression<S> and all vector expressions V have to derive from vector_expression<V>. This way this operator is only considered if the fist operand is really an expression for a vector and the second argument is really an expression for a scalar. You can overload this function template with a second one that swaps both parameters and everything is okay.

Now, to be able to access anything from V and S (the derived types) we need a cast from base class to derived class. This is what the conversion operator in the base class is for. Since the base class knows the derived class (it is a template parameter), this is not a problem. It makes sense to choose the weakest cast operator that allows this cast to avoid errors. This is the static_cast. It can be used to convert base* to derived* without any significant overhead.

I don't understand what you try to do with your code

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

If you want to write your own vector expression as a template you would do it like this:

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

I don't think it works with private inheritance. At least all the function templates that take a vector expression as argument won't be able to access the conversion operator from the base class if you use private inheritance here.


Solution:2

The accessibility error that you are referring to does not make sense. vector_expression is a struct and the function call operator () is public. Perhaps you tried to invoke vector_expression2::operator ()? That would have given you an error because you defined that operator as private.

The solution to you problem might be even simpler than you think. If you look through the ublas source code you would see that any classes deriving vector_expression pass themselves as the template argument:

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

What this means is that vector_expression can cast the template parameter to itself because the template parameter derives from vector_expression, hence *static_cast<const E*>(this) works, which is just a fancy way to say *((const E*)this).

Try to rewrite vector_expression2 class like so:

template<class E>  class vector_expression2 : public vector_expression<vector_expression2<E>>  {  };  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »