首页 > 解决方案 > 不同的模板类实现但相同的成员函数

问题描述

我有一个模板矩阵类,其中包含一些典型的成员函数,例如inversedeterminantoperator*等。我想在模板实现中重用这些成员函数的代码,用于固定动态大小的矩阵。 这可能吗?如果是,如何?

在下面的代码中,像 Eigen 一样,我使用 " -1" 表示动态尺寸。是的,我知道我可以为此使用库,但对于我的应用程序,这是不可行的。由于应用程序的性质(CUDA),标准功能是不可能的

是否可以根据模板参数制作具有不同成员变量大小的模板类?例如 whenDynamic_Rows = -1Dynamic_Cols = -1,则数据为T **data,否则为T data[Rows][Cols]

到目前为止,我有一个用于动态大小矩阵的模板类(下面的“最小”示例,请注意代码可能会出现错误/错误,因为我对“高级”类模板比较陌生)。

但是在固定大小的矩阵实例化的情况下,我希望有一个固定大小的数据成员变量。

template<class T, int Dynamic_Rows, int Dynamic_Cols>
class CMatrix<T, -1, -1>
{
private:
   size_t n_rows, n_cols;
   T** data;

   void allocate_data();
   void deallocate_data();

public:
   CMatrix(const size_t n_rows, const size_t n_cols);
   CMatrix(const CMatrix& other);
   ~CMatrix();
   CMatrix& operator=(const CMatrix& rhs);
   CMatrix exp() const;
};

例如exp()下面函数的代码为

template <class T, int Dynamic_Rows, int Dynamic_Cols>
CMatrix<T, -1, -1> CMatrix<T, -1, -1>::exp() const
{
   CMatrix<T, -1, -1> result(n_rows, n_cols);
   for (size_t i = 0; i < n_rows; i++)
   {
      for (size_t j = 0; j < n_cols; j++)
      {
         result.data[i][j] = exp(result.data[i][j]);
      }
   }
   return result;
}

我现在唯一能想到的同时允许动态和固定大小的矩阵是基本上实现该类的另一个模板作为

template<class T, size_t Rows, size_t Cols>
class CMatrix<T, Rows, Cols>
{
private:
   size_t n_rows = Rows, n_cols = Cols;
   T data[Rows][Cols];

public:
   CMatrix() {}
   CMatrix(const CMatrix& other);
   CMatrix& operator=(const CMatrix& rhs);
   CMatrix exp() const;
};

使用可变参数模板

template<class T, int...> class CMatrix;

但这只会复制我的大多数成员函数的代码!

标签: c++c++11templatestemplate-specializationclass-template

解决方案


这是使用 CRTP 进行此类专业化的一种非常通用的方法。它不要求有一个简单的单一条件可用于选择数据成员的实现,而其余部分保持不变。

template <class T, class Impl> class MatrixBase {

   // data is NOT defined here
   Impl exp() const
   {
        Impl& self = static_cast<Impl&>(*this);             // <-- this is magic
        Impl result = self;                                 // <-- this is magic
        for (size_t i = 0; i < n_rows; i++)
        {
            for (size_t j = 0; j < n_cols; j++)
            {
                result.data[i][j] = exp(result.data[i][j]); // <-- data is defined in Impl
            }
        }
        return result;
    }
    // other functions that do not depend on actual type of data
};

template <class T>
class DynamicMatrix : public MatrixBase<T, DynamicMatrix<T>> {
    T** data;
    // define constructors etc here
};

template <class T, int Rows, int Cols>
class StaticMatrix : public MatrixBase<T, StaticMatrix<T, Rows, Cols>> {
    T[Rows][Cols] data;
    // define constructors etc here
};

现在您已经拥有了StaticMatrixand DynamicMatrix,如果您愿意,可以将它们统一为一个别名模板。

template <class T, int Rows, int Cols>
using CMatrix = std::conditional_t <(Rows >= 0 && Cols >= 0),
                                     StaticMatrix<T, Rows, Cols>,
                                     DynamicMatrix<T>
                                   >;

推荐阅读