可变参数模板
本文介绍可变参模板的基本概念与用法,大量参考了cppreferen内容,可以说是对其的整理与总结。
c++11特性引入可变模板参数这一特性,这使得可以含有不定个数参数的模板类和模板参数得以实现。如下代码:
变参数模板类如下:
// 变参数模板类
template
struct Tuple {};
Tuple<> t0; // Types 不包含实参
Tuple t1; // Types 包含一个实参:int
Tuple t2; // Types 包含二个实参:int 与 float
Tuple<0> error; // 错误:0 不是类型
变参数模板函数如下:
template
void f(Types ... args);
f(); // OK:args 不包含实参
f(1); // OK:args 包含一个实参:int
f(2, 1.0); // OK:args 包含二个实参:int 与 double
那么变参类与变参函数该如何使用呢?这篇文章将带你了变参的解模板类与模板函数,教你如何使用。
模板参数可以分为形参与实参,类似于函数中的形参与实参:形参是变量声明,实参是变量具体值。模板里形参就是类型(或值)声明,实参是你想传入的类型。可以参考cppreference,简单的说如下:
template < 形参列表 > 声明
Tuple t1; // Types 包含一个实参:int
知道了模板的形参与实参的概念再来理解下形参的包——形参包
模板形参包是接受零或更多模板实参(非类型、类型或模板)的模板形参。函数模板形参包是接受零或更多函数实参的函数形参。至少有一个形参包的模板被称作变参模板。
——cppreference
模板形参包(出现于别名模版、类模板、变量模板及函数模板形参列表中),定义如下:
类型 … Args(可选) (1)
typename|class … Args(可选) (2)
template < 形参列表 > typename(C++17)|class … Args(可选) (3)
——cppreference
以上是官方的定义,简单的说我们变参的模板类或者模板函数的模板声明可以是如下:
template // typename ... Types 为形参包
struct Tuple {};
template // typename ... Types 为形参包
void f(Types ... args);
模板函数中的参数该如何写呢?
函数模板参数包定义如下:
Args … args(可选)
如代码:
template
void f(Types ... args); // Types ... args 为函数模板的参数包
在函数中或类中使用形参包时必须先将其展开。
形式;
模式 …
定义如下:
模式后随省略号,其中至少有一个形参包的名字至少出现一次,其被展开成零或更多个逗号分隔的模式实例,其中形参包的名字按顺序被替换成包中的各个元素。
如下代码:
// 代码1
template void f(Us... pargs) {}
template void g(Ts... args) {
f(&args...); // “&args...” 是包展开
// “&args” 是其模式
}
g(1, 0.2, "a"); // Ts... args 展开成 int E1, double E2, const char* E3
// &args... 展开成 &E1, &E2, &E3
// Us... 展开成 int* E1, double* E2, const char** E3
代码中f(&args...)
中展开为f(&E1, &E2, &E3)
, 若改为f(&args)...
,则展开为f(&E1),f(&E1),f(&E1)
,当然这样会编译报错。
又如下代码:
// 代码2
template struct Tuple {};
template struct Pair {};
template struct zip {
template struct with {
typedef Tuple...> type;
// Pair... 是包展开
// Pair 是模式
};
};
typedef zip::with::type T1;
// Pair... 展开成
// Pair, Pair
// T1 是 Tuple, Pair>
技巧:递归包展开
可以采用递归调用的方式来定义模板函数
template
T Sum(T data) {
return data;
}
template
T Sum(T data, Args... args) {
return data + Sum(args...);
}
int main() {
std::cout << Sum(1, 2, 3, 4) << std::endl; // 输出 10
std::cout << Sum(1) << std::endl; // 输出 1
return 0;
}
一个变参模板可以有以下步骤
template
f(Args ... args)
f(args...)
或f(args)...