基于模板函数参数的指针级别 return 类型
Pointer level return type based on template function arguments
对于张量 class 我想要一个创建函数的模板,例如
double* mat(int size1);
double** mat(int size1, int size2);
double*** mat(int size1, int size2, int size3);
即return 类型的指针级别取决于输入的数量。
基本情况就是
double* mat(int size1){
return new double[size1];
}
我认为可变参数模板可以以某种方式解决问题
template<typename T, typename... size_args>
T* mat(int size1, size_args... sizes) {
T* m = new T[size1];
for(int j = 0; j < size1; j++){
m[j] = mat(sizes...);
}
return m;
}
推导 m[j] = mat(sizes...);
中的模板参数似乎不起作用,尽管需要多次递归调用,如
auto p = mat<double**>(2,3,4);
但是我如何在递归调用中提供参数?正确的参数应该是 T
以下一个指针级别,即 T=double***
的 mat<double**>
。
我觉得我在这里错过了一些关于模板的重要内容。
您不能将 m
和 return 类型声明为 T*
,因为它不在多维度中。
template<typename T, typename size_type>
auto mat(size_type size){return new T[size];}
template<typename T, typename size_type, typename... size_types>
auto mat(size_type size, size_types... sizes){
using inner_type = decltype(mat<T>(sizes...));
inner_type* m = new inner_type[size];
for(int j = 0; j < size; j++){
m[j] = mat<T>(sizes...);
}
return m;
}
由于找不到更好的名称,我将调用模板 meta-function,它创建一个具有所需“深度”和类型的指针类型,即“递归指针”。这样的事情可以这样实现:
template <size_t N, class T>
struct RecursivePtr
{
using type = RecursivePtr<N-1, T>::type*;
};
template <class T>
struct RecursivePtr<0, T>
{
using type = T;
};
template <size_t N, class T>
using recursive_ptr_t = RecursivePtr<N, T>::type;
例如 recursive_ptr_t<4, int>
创建 int****
。因此,在您的情况下,您可以继续将 mat
函数实现为:
template <class... Args>
auto mat(Args... args)
{
recursive_ptr_t<sizeof...(Args), double> m;
// Runtime allocate your Npointer here.
return m;
}
为 mat 函数增加类型安全性的一些想法是:
- 添加静态断言所有提供的类型都是大小
- 静态断言至少提供了一种尺寸
注意,当我在上面说运行时分配你的 Npointer 时,我的意思是:
template <class T, class... Sz>
void alloc_ar(T* &ar, size_t s1, Sz... ss)
{
if constexpr (sizeof...(Sz))
{
ar = new T[s1];
for (size_t i(0); i < s1; i++)
alloc_ar(ar[i], ss...);
}
else
{
ar = new T[s1];
}
}
制作了一个 Demo,其中我显示了分配,但没有显示释放。
一个合理的替代方案是分配一个连续的内存块(大小 == 维度的倍数)并在访问它时使用指向该块开头的多维指针作为语法糖。这也提供了一种更简单的方法来释放内存。
第二种选择是使用嵌套的向量向量(向量的向量...),其生成机制与 Npointer 相同。这消除了手动内存管理的需要,并且可能会迫使您将整个事情包装在更具表现力的 class:
template <class... Dims>
class mat
{
template <size_t N, class T>
struct RecursivePtr
{
using type = std::vector<RecursivePtr<N-1, T>::type>;
};
template <class T>
struct RecursivePtr<0, T>
{
using type = T;
};
// This is the replacement to double***
// translates to vector<vector<vector<double>>>
RecursivePtr<N, T>::type _data;
public:
// construction, argument deduction etc ...
};
对于张量 class 我想要一个创建函数的模板,例如
double* mat(int size1);
double** mat(int size1, int size2);
double*** mat(int size1, int size2, int size3);
即return 类型的指针级别取决于输入的数量。 基本情况就是
double* mat(int size1){
return new double[size1];
}
我认为可变参数模板可以以某种方式解决问题
template<typename T, typename... size_args>
T* mat(int size1, size_args... sizes) {
T* m = new T[size1];
for(int j = 0; j < size1; j++){
m[j] = mat(sizes...);
}
return m;
}
推导 m[j] = mat(sizes...);
中的模板参数似乎不起作用,尽管需要多次递归调用,如
auto p = mat<double**>(2,3,4);
但是我如何在递归调用中提供参数?正确的参数应该是 T
以下一个指针级别,即 T=double***
的 mat<double**>
。
我觉得我在这里错过了一些关于模板的重要内容。
您不能将 m
和 return 类型声明为 T*
,因为它不在多维度中。
template<typename T, typename size_type>
auto mat(size_type size){return new T[size];}
template<typename T, typename size_type, typename... size_types>
auto mat(size_type size, size_types... sizes){
using inner_type = decltype(mat<T>(sizes...));
inner_type* m = new inner_type[size];
for(int j = 0; j < size; j++){
m[j] = mat<T>(sizes...);
}
return m;
}
由于找不到更好的名称,我将调用模板 meta-function,它创建一个具有所需“深度”和类型的指针类型,即“递归指针”。这样的事情可以这样实现:
template <size_t N, class T>
struct RecursivePtr
{
using type = RecursivePtr<N-1, T>::type*;
};
template <class T>
struct RecursivePtr<0, T>
{
using type = T;
};
template <size_t N, class T>
using recursive_ptr_t = RecursivePtr<N, T>::type;
例如 recursive_ptr_t<4, int>
创建 int****
。因此,在您的情况下,您可以继续将 mat
函数实现为:
template <class... Args>
auto mat(Args... args)
{
recursive_ptr_t<sizeof...(Args), double> m;
// Runtime allocate your Npointer here.
return m;
}
为 mat 函数增加类型安全性的一些想法是:
- 添加静态断言所有提供的类型都是大小
- 静态断言至少提供了一种尺寸
注意,当我在上面说运行时分配你的 Npointer 时,我的意思是:
template <class T, class... Sz>
void alloc_ar(T* &ar, size_t s1, Sz... ss)
{
if constexpr (sizeof...(Sz))
{
ar = new T[s1];
for (size_t i(0); i < s1; i++)
alloc_ar(ar[i], ss...);
}
else
{
ar = new T[s1];
}
}
制作了一个 Demo,其中我显示了分配,但没有显示释放。
一个合理的替代方案是分配一个连续的内存块(大小 == 维度的倍数)并在访问它时使用指向该块开头的多维指针作为语法糖。这也提供了一种更简单的方法来释放内存。
第二种选择是使用嵌套的向量向量(向量的向量...),其生成机制与 Npointer 相同。这消除了手动内存管理的需要,并且可能会迫使您将整个事情包装在更具表现力的 class:
template <class... Dims>
class mat
{
template <size_t N, class T>
struct RecursivePtr
{
using type = std::vector<RecursivePtr<N-1, T>::type>;
};
template <class T>
struct RecursivePtr<0, T>
{
using type = T;
};
// This is the replacement to double***
// translates to vector<vector<vector<double>>>
RecursivePtr<N, T>::type _data;
public:
// construction, argument deduction etc ...
};