带有参数包的模板专业化
Template specialization with Parameter Packs
我对 c++ 很陌生,但想尝试做一些花哨的模板。我不确定这是否可能,但我相当有信心有办法实现这一目标。
问题来了:
我正在调用各种硬件函数,它需要多个参数并且只有一种参数类型不同:
int Read(HANDLE handle, int location, char* Name, int startindex1, int endindex1,
int startindex2, int endindex2, int* rval, Astruct* callback) ;
int Read(HANDLE handle, int location, char* Name, int startindex1, int endindex1,
int startindex2, int endindex2, double* rval, Astruct* callback) ;
硬件接口returns 标量、数组或矩阵,具体取决于索引的值。我真正想要实现的是一个函数,它 returns 一个 T
或 vector<T>
或 vector<vector<T>>
取决于我传递的参数数量。:
T MyReadFunction<T>(HANDLE handle, int location, char* Name,int index)
vector<T> MyReadFunction<T>(HANDLE handle, int location, char* Name,int startindex1,
int endindex1 )
vector<vector<T>> MyReadFunction<T>(HANDLE handle, int location, char* Name,int startindex1,
int endindex1
int startindex2,
int endindex2)
其中 T
是基本类型,例如 int
、real
、float
、double
等
使用 3 个具有专业化的不同模板没有问题,但我很想以某种方式将其组合起来。
我的假设是,这可以使用模板专业化来实现,但我无法理解它。我想我应该这样:
template<typename T ,int... Indexes>
T MyReadFunction (HANDLE handle, int location, char* Name, Indexes... myIndex){}
template<>
int MyReadFunction (HANDLE handle, int location, char* Name, int myindex)
{
int rval = 0;
Read (handle,location,name,myindex,myindey,0,0,&rval, NULL) ;
return rval;
}
这是一头双头野兽。我可能需要明确地实现我的 3 个案例以避免误用,但我也想知道,我如何根据参数包的大小,通过不同大小的参数包实现模板专业化。
我在 VS 2019 中使用最新的 msvc++
您可以编写一个类型来创建所需等级的嵌套向量,如下所示:
template<typename T,int N>
struct VT
{
using type = typename std::vector<typename VT<T, N - 1>::type>;
};
template<typename T>
struct VT<T, 0>
{
using type = int;
};
然后像这样写一个函数:
template<typename T ,typename ...Indexes>
typename VT<T, sizeof...(Indexes) / 2>::type
MyReadFunction (int handle, int location, char* Name, Indexes... myIndex) {}
这是一个demo。
如您所见,这样做并没有多大意义,因为函数体的实现会变得相当棘手。简单地编写特化或重载将是一个更简单的解决方案。
请注意,如果您选择编写此函数模板,myIndex
参数包不受约束,即它将接受 int
以外的类型。当然,您可以通过多写一点代码来限制它。
此外,此函数模板将接受大小为 3、5、7 等的 Indexes
,这可能不是您想要的。同样,您也可以通过编写更多代码来限制它。
cigien 对这个关于参数包的问题有很好的回答。
这是另一个不使用包的解决方案。参数包是 type-lists,但你实际上不需要改变 N 种类型,你只需要一个 N-dimensional 数组。
如果将索引列表放在花括号内,则可以将其视为长度为 compile-time 的列表。
不过,在我看来,标量情况可能无法很好地从多维情况中概括出来。标量情况采用单个索引,而数组需要每个维度的开始和结束索引。
template<typename T,int N>
struct VT
{
using type = typename std::vector<typename VT<T, N - 1>::type>;
};
template<typename T>
struct VT<T, 0>
{
using type = T;
};
template< typename T, int n >
std::enable_if_t< n == 1 || n % 2 == 0,
typename VT<T, n/2>::type >
MyReadFunction( HANDLE handle, int location, char* Name, int const (&indexes)[n] );
// usage: MyReadFunction< double >( inputFile, 123, "name", { 1, 2, 3, 4 } );
// yields vector< vector< double > >
我对 c++ 很陌生,但想尝试做一些花哨的模板。我不确定这是否可能,但我相当有信心有办法实现这一目标。
问题来了: 我正在调用各种硬件函数,它需要多个参数并且只有一种参数类型不同:
int Read(HANDLE handle, int location, char* Name, int startindex1, int endindex1,
int startindex2, int endindex2, int* rval, Astruct* callback) ;
int Read(HANDLE handle, int location, char* Name, int startindex1, int endindex1,
int startindex2, int endindex2, double* rval, Astruct* callback) ;
硬件接口returns 标量、数组或矩阵,具体取决于索引的值。我真正想要实现的是一个函数,它 returns 一个 T
或 vector<T>
或 vector<vector<T>>
取决于我传递的参数数量。:
T MyReadFunction<T>(HANDLE handle, int location, char* Name,int index)
vector<T> MyReadFunction<T>(HANDLE handle, int location, char* Name,int startindex1,
int endindex1 )
vector<vector<T>> MyReadFunction<T>(HANDLE handle, int location, char* Name,int startindex1,
int endindex1
int startindex2,
int endindex2)
其中 T
是基本类型,例如 int
、real
、float
、double
等
使用 3 个具有专业化的不同模板没有问题,但我很想以某种方式将其组合起来。
我的假设是,这可以使用模板专业化来实现,但我无法理解它。我想我应该这样:
template<typename T ,int... Indexes>
T MyReadFunction (HANDLE handle, int location, char* Name, Indexes... myIndex){}
template<>
int MyReadFunction (HANDLE handle, int location, char* Name, int myindex)
{
int rval = 0;
Read (handle,location,name,myindex,myindey,0,0,&rval, NULL) ;
return rval;
}
这是一头双头野兽。我可能需要明确地实现我的 3 个案例以避免误用,但我也想知道,我如何根据参数包的大小,通过不同大小的参数包实现模板专业化。
我在 VS 2019 中使用最新的 msvc++
您可以编写一个类型来创建所需等级的嵌套向量,如下所示:
template<typename T,int N>
struct VT
{
using type = typename std::vector<typename VT<T, N - 1>::type>;
};
template<typename T>
struct VT<T, 0>
{
using type = int;
};
然后像这样写一个函数:
template<typename T ,typename ...Indexes>
typename VT<T, sizeof...(Indexes) / 2>::type
MyReadFunction (int handle, int location, char* Name, Indexes... myIndex) {}
这是一个demo。
如您所见,这样做并没有多大意义,因为函数体的实现会变得相当棘手。简单地编写特化或重载将是一个更简单的解决方案。
请注意,如果您选择编写此函数模板,myIndex
参数包不受约束,即它将接受 int
以外的类型。当然,您可以通过多写一点代码来限制它。
此外,此函数模板将接受大小为 3、5、7 等的 Indexes
,这可能不是您想要的。同样,您也可以通过编写更多代码来限制它。
cigien 对这个关于参数包的问题有很好的回答。
这是另一个不使用包的解决方案。参数包是 type-lists,但你实际上不需要改变 N 种类型,你只需要一个 N-dimensional 数组。
如果将索引列表放在花括号内,则可以将其视为长度为 compile-time 的列表。
不过,在我看来,标量情况可能无法很好地从多维情况中概括出来。标量情况采用单个索引,而数组需要每个维度的开始和结束索引。
template<typename T,int N>
struct VT
{
using type = typename std::vector<typename VT<T, N - 1>::type>;
};
template<typename T>
struct VT<T, 0>
{
using type = T;
};
template< typename T, int n >
std::enable_if_t< n == 1 || n % 2 == 0,
typename VT<T, n/2>::type >
MyReadFunction( HANDLE handle, int location, char* Name, int const (&indexes)[n] );
// usage: MyReadFunction< double >( inputFile, 123, "name", { 1, 2, 3, 4 } );
// yields vector< vector< double > >