不同的模板类实现,但成员函数相同

问题描述

我有一个模板矩阵类,其中包含一些典型的成员函数,例如def returnCode = mockRequest.getRequest().getParameter("returnCode") if( returnCode.equals("429")) { return "Response 429" } else if( returnCode.equals("500")) { return "Response 500" } else { return "Response 200" } inversedeterminant等。并且我想在模板中为这些成员函数重用代码固定-和动态大小矩阵的实现。 这可能吗?如果可以,怎么办?

在下面的代码中,像Eigen一样,我将“ operator*”用于动态尺寸。是的,我知道我可以为此使用一个库,但是对于我的应用程序,那是不可行的。 由于应用程序(CUDA)的性质,无法使用标准功能

是否可以根据模板参数使模板类具有不同的成员变量大小?例如,当-1Dynamic_Rows = -1时,数据仅为{ {1}},否则为Dynamic_Cols = -1

到目前为止,我有一个用于动态尺寸矩阵的模板类(以下示例为“ minimum ”,请注意,该代码容易出错/出错,因为我在“高级”类中相对较新)模板)。

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

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_Cols>
CMatrix<T,-1> CMatrix<T,-1>::exp() const
{
   CMatrix<T,-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;
}

但是那只会复制我大多数成员函数代码

解决方法

这是使用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
};

现在您同时拥有StaticMatrixDynamicMatrix,可以根据需要将它们统一为一个别名模板。

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

是否可能.... [...] ...当Dynamic_Rows = -1Dynamic_Cols = -1时,数据仅为T **data,否则为T data[Rows][Cols]

您可以提供特征类型,其特征可以为CMatrix提供适当的类型

template<typename T,int Cols> struct type_helper final {
    static_assert(Rows >= 0 && Cols >= 0,"Rows and COls must be valid!");
    using type = T[Rows][Cols];
};

template<typename T> struct type_helper<T,-1,-1>  final {
    using type = T**;
};

现在上课了

template<class T,int Dynamic_Rows = -1,int Dynamic_Cols = -1>
class CMatrix /* final */
{
    // get the member Type like this!
    using Type = typename type_helper<T,Dynamic_Rows,Dynamic_Cols>::type;

    Type data;
public:

};

See a demo online

,

您可以使用std::conditional_t根据一些编译时常量选择一种或另一种类型,而无需复制类。

但是-我曾经做过非常类似的事情,发现使用固定大小的数据结构(std::array而不是std::vector)在实际使用案例中几乎没有改善。 固定大小的数组(std::arraytype[fixed_size])的一个很大的优点是编译器能够优化很多操作,但是如果数组很大,则好处可以忽略不计。

此外,您应该考虑 n。 “代词” m。的注释-特别是如果您使用的是GPU(它们往往需要内存中连续的数据结构)。代替使用T** data,在每个维度上使用单个std::vector<T>,并使用附加的std::array<size_t,number_of_dimensions>。然后,您可以使用以下方式转换索引:

using Indices = std::array<size_t,number_of_dimensions>;

template <unsigned int n = number_of_dimensions>
static inline size_t indices_to_offset(Indices const & indices,Indices const & dimensions){
    if constexpr (n == 0) return 0;
    else {
        size_t const next_index_number = indices[n-1];
        assert(next_index_number < dimensions[n-1]);
        return next_index_number +
            dimensions[n-1]*indices_to_offset<n-1>(indices,dimensions);
    }
}

template <unsigned int n = number_of_dimensions>
static inline Indices offset_to_indices(size_t const offset,Indices const & dimensions,Indices indices = Indices()){
    if constexpr (n == 0) return indices;
    else {
        size_t const fast_dimension_size = dimensions[n-1];
        indices[n-1] = offset % fast_dimension_size;
        return offset_to_indices<n-1>(offset/fast_dimension_size,dimensions,indices);
    }
}
,

将我的评论变成答案(使用rectangle代替Vector):

拆分您的课程,因此您有一部分专门研究特定的课程,而共有部分则是类似的:

Matrix

然后是公共部分:

// helper to allow variadic constructor without pitfall.
constexpr struct in_place_t{} in_place{};

template <typename T,std::size_t DIM>
class VectorData
{
protected: // You might even make it private and give the common accessor in public part
           // To avoid to use interface not shared with std::vector
    std::array<T,DIM> data;
public:
    VectorData() = default;

    template <typename ... Ts>
    VectorData(in_place_t,Ts&&... args) : data{std::forward<Ts>(args)...} {}
};

template <typename T>
class VectorData<T,std::size_t(-1)>
{
protected: // You might even make it private and give the common accessor in public part
           // To avoid to use interface not shared with std::array
    std::vector<T> data;
public:
    explicit VectorData(std::size_t size) : data(size) {}

    template <typename ... Ts>
    VectorData(in_place_t,Ts&&... args) : data{std::forward<Ts>(args)...} {}
};

Demo

相关问答

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