带有参数包的模板专业化

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 一个 Tvector<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 是基本类型,例如 intrealfloatdouble

使用 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 > >