代码之家  ›  专栏  ›  技术社区  ›  Anycorn

C++继承模式+CRTP

  •  0
  • Anycorn  · 技术社区  · 16 年前

    我试图理解ublas中使用的模式。 模式如下:

    struct vector : vector_expression<vector>
    

    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 回复  |  直到 16 年前
        1
  •  2
  •   sellibitze    16 年前

    这是一个约束函数模板的技巧——约束类型的类。有很多概念,如向量表达式、标量表达式、矩阵表达式等。如果您想编写一个函数模板,将向量与标量相乘,您可以尝试编写

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

    为了实现这一点,所有标量表达式都必须从中派生 scalar_expression<S> 所有的向量表达式都必须从 vector_expression<V> . 这样,只有当第一个操作数实际上是向量的表达式,而第二个参数实际上是标量的表达式时,才考虑此运算符。您可以使用第二个函数模板重载此函数模板,该模板交换两个参数,并且一切正常。

    现在,为了能够访问V和S(派生类型)中的任何内容,我们需要一个从基类到派生类的转换。这就是基类中的转换运算符的作用。因为基类知道派生类(它是一个模板参数),所以这不是问题。选择最弱的cast操作符可以避免错误。这就是 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> >;
    

        2
  •  1
  •   Igor Zevaka    16 年前

    您所指的可访问性错误没有意义。 vector_expression 是一个 struct 以及函数调用 operator () 是公开的。也许你想 vector_expression2::operator () ? 这会给您一个错误,因为您将该操作符定义为private。

    解决你的问题可能比你想象的还要简单。如果您仔细查看ublas源代码,就会发现 将其自身作为模板参数传递:

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

    这意味着 无法将模板参数强制转换为自身,因为模板参数派生自 ,因此 *static_cast<const E*>(this) *((const E*)this) .

    试着重写 vector_expression2 像这样的班级:

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