问题描述
我有一个模板矩阵类,其中包含一些典型的成员函数,例如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"
}
,inverse
,determinant
等。并且我想在模板中为这些成员函数重用代码固定-和动态大小矩阵的实现。
这可能吗?如果可以,怎么办?
在下面的代码中,像Eigen一样,我将“ operator*
”用于动态尺寸。是的,我知道我可以为此使用一个库,但是对于我的应用程序,那是不可行的。 由于应用程序(CUDA)的性质,无法使用标准功能
是否可以根据模板参数使模板类具有不同的成员变量大小?例如,当-1
和Dynamic_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
};
现在您同时拥有StaticMatrix
和DynamicMatrix
,可以根据需要将它们统一为一个别名模板。
template <class T,int Cols>
using CMatrix = std::conditional_t <(Rows >= 0 && Cols >= 0),Cols>,DynamicMatrix<T>
>;
,
是否可能.... [...] ...当
Dynamic_Rows = -1
和Dynamic_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:
};
,
您可以使用std::conditional_t根据一些编译时常量选择一种或另一种类型,而无需复制类。
但是-我曾经做过非常类似的事情,发现使用固定大小的数据结构(std::array
而不是std::vector
)在实际使用案例中几乎没有改善。
固定大小的数组(std::array
或type[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)...} {}
};