CRTP:确定基类函数中的派生类类型以允许代码重用

问题描述

让我们说我有一个用于矩阵的CRTP模板类

template<class T,class Derived>
class MatrixBase{
private:
    //...

public:
    Derived some_function(const Derived &other){
          Derived& self = (Derived&)*this; // In my application I cant use static_cast.

          // Some calculations...,which will determine the below 
          // defined variables "some_number_of_rows" and "some_number_of_cols"

          // If Derived = DynamicMatrix<T>,then result should be declared as:
          DynamicMatrix<T> result(some_number_of_rows,some_number_of_cols);

          // while if Derived = StaticMatrix<T,Rows,Cols>,then result should be declared as:
          StaticMatrix<T,some_number_of_rows,some_number_of_cols> result;

          // Perform some more calculations...

          return result;
    }
};

template<class T>
class DynamicMatrix{
private:
     size_t n_rows,n_cols;
     T *data;
public:
     DynamicMatrix(const size_t n_rows,const size_t n_cols);
     // ...
};

template<class T,int Rows,int Cols>
class StaticMatrix{
private:
     size_t n_rows = Rows,n_cols = Cols;
     T data[Rows * Cols];
public:
     StaticMatrix() {}
     // ...
};

如何在MatrixBase::some_function(const Derived &other)中检查派生类类型以在两个派生类中使用此基函数,从而避免了分别在这些类中重新定义/覆盖/重复代码的需求。在这种情况下,基本上只有result矩阵的声明才需要我检查Derived类的类型,因为该声明根据其固定大小或动态矩阵而有所不同。除类型检查外,也欢迎使用其他解决方案。

注意:由于我的应用程序的性质,我无法使用标准功能

编辑:示例函数中的some_number_of_rowssome_number_of_cols通常不是constexpr,因为它们取决于对象矩阵的功能和大小。例如,对于transpose函数,结果必须具有维度<Derived.n_cols,Derived.n_rows,对于列式点积为<1,Derived.n_cols>

解决方法

这是一个具有挑战性的问题。基本上,some_number_of_rows的{​​{1}}和some_number_of_cols 必须constexpr,而{em不能为{{1} } StaticMatrix

一种解决方案是将新的矩阵创建委托给派生类。它将以constexpr或不以DynamicMatrix的形式进行大小计算,以二者为准。

另一种方法是在CRTP类中进行两次大小计算,一次为constexpr,另一次为constexpr,并将两个结果都传递给派生的对象创建函数:constexpr作为模板参数传递,非constexpr作为常规参数传递。创建函数专门用于静态和动态矩阵。静态版本会忽略非constexpr参数,反之亦然。

,

据我了解,您可以在Derived中添加这些工厂方法:

如果在两种情况下,some_number_of_rowssome_number_of_cols都可以是constexpr(以满足更受​​约束的Derived),则可以执行以下操作:

template<class T>
class DynamicMatrix
{
  // ...
  template <std::size_t Row,std::size_t Col>
  static DynamicMatrix<T> Create() { return DynamicMatrix(Row,Col); }
};

template <class T,int Rows,int Cols>
class StaticMatrix{
  // ...
  template <std::size_t Row,std::size_t Col>
  static StaticMatrix<T,Row,Col> Create() { return {}; }
};

使用

auto result = Derived::Create<some_number_of_rows,some_number_of_cols>();

否则,您也必须将计算移到派生函数中:

template<class T>
class DynamicMatrix
{
  // ...
  DynamicMatrix<T> CreateEmptyTransposed() const { return DynamicMatrix(n_cols,n_rows); }
};

template <class T,int Cols>
class StaticMatrix{
  // ...
  StaticMatrix<T,Cols,Row> CreateEmptyTransposed() const { return {}; }
};

使用

auto result = self.CreateEmptyTransposed();

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...