C ++继承模式+ CRTP

时间:2010-07-20 04:53:15

标签: c++ inheritance

我正在尝试了解ublas中使用的模式。 模式是这样的:

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 个答案:

答案 0 :(得分:2)

这是限制函数模板的技巧 - 限制类型类。有很多概念,如矢量表达式,标量表达式,矩阵表达式等。如果你想编写一个函数模板,它将一个矢量与一个标量相乘,你可以尝试编写

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。它可用于将base *转换为派生*而不会产生任何显着的开销。

我不明白你尝试用你的代码做什么

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 :(得分:1)

您所指的辅助功能错误没有意义。 vector_expressionstruct,函数调用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) 1}}。

尝试重写vector_expression2类,如下所示:

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