1.变长模板
1.1.变长模板定义
支持不限制数量的模板参数
// tuple是一个模板类
// 模板形参:可变数量的类型
template <typename... Elements>
class tuple{}
tuple<int, char, double> a;
// NonTypeVar是一个模板类
// 模板形参:可变数量的int类型数值
template<int... A>
class NonTypeVar{};
NonTypeVar<1, 0, 2> aa;
1.2.变长模板使用
(1).使用模板参数包
#include <iostream>
// B是一个模板类
// 模板形参:两个类型
template<typename T1, typename T2>
class B {
};
// B<int, double>是一个特化的模板类
// 模板形参:int,double
template <>
class B<int, double> {
public:
B() {
printf("B<int,double>\n");
}
};
// Temp是一个模板类
// 模板形参:可变数量的类型
// A...代表对typename... A为代表的部分的一个引用。
template<typename... A>
class Temp:private B<A...> {
};
// 这个xy将私有继承B<int, double>
Temp<int, double> xy;
int main(){
return 0;
}
(2).对可变参数模板结合模板特化展开
#include <iostream>
// tuple是一个模板类
// 模板形参:可变个数类型
template<typename... E>
class tuple{
public:
tuple(){
printf("normal\n");
}
};
// tuple<Head, Tail...>是一个特化模板类
// 模板形参:可变个数类型。从第二到最后一个类型可通过Tail...来整体引用
template<typename Head, typename... Tail>
class tuple<Head, Tail...>:private tuple<Tail...>{
public:
tuple(){printf("sizeof_%d\n", sizeof(Head));}
Head h;
};
// tuple<>是一个特化模板类
// 模板形参:空
template<>
class tuple<>{
public:
tuple(){
printf("null\n");
}
};
tuple<double,short,char,float> a;
int main(){
return 0;
}
另一个等价实例
#include <iostream>
using namespace std;
template<long... num>
struct Multiply{};
template<long first, long... last>
struct Multiply<first, last...>{
static const long val = first * Multiply<last...>::val;
};
template<>
struct Multiply<>{
static const long val = 1;
};
int main(){
cout << Multiply<2,3,4,5>::val << endl;
return 0;
}
(3).基于变长模板的模板函数
// f是一个模板函数
// 函数形参:可变个数类型的变量
template<typename... T>
void f(T... args){
}
int main(){
f(1, 1.0);//实例化为f(int a, double b)
f(1);//实例化为f(int)
}
利用模板参数包,函数参数包可实现c
的变长函数的一个实例
#include <iostream>
#include <stdexcept>
using namespace std;
void Printf(const char* s){
while(*s){
if(*s == '%' && *++s != '%'){
throw runtime_error("invalid format string: missing arguments");
}
cout << *s++;
}
}
// Printf是一个模板函数
// 函数形参:首个参数必须是const char*,第二个参数必须是某个类型,第三到最后为可变数量个类型
template<typename T, typename... Args>
void Printf(const char* s, T value, Args... args){
while(*s){
if(*s == '%' && *++s != '%'){
cout << value;
return Printf(++s, args...);
}
cout << *s++;
}
throw runtime_error("extra arguments provided to Printf");
}
int main(){
Printf("hello %s\n", string("world"));
return 0;
}
c
的可变参数函数printf
必须依赖对格式化字符串的解析,来提取每个可变参数。
借助可变参数模板,可以不依赖格式化字符串,借助模板类型推导,可变参数包来依次得到每个模板参数的类型和实参。
(4).使用参数包时允许添加修饰符
#include <iostream>
using namespace std;
template<typename... T>
void DummyWrapper(T... t){
}
template<typename T>
T pr(T t){
cout << t;
return t;
}
// VTPrint是一个模板函数
// 函数形参:可变数量的类型
template<typename... A>
void VTPrint(A... a){
// 通过a...可以整体引用A... a
// 通过pr(a)...,相当于整体引用A... a时,对其中每个元素t引用的是pr(t)
DummyWrapper(pr(a)...);
}
int main(){
VTPrint(1, ", ", 1.2, ", abc\n");
cout << endl;
return 0;
}
打印顺序不符合实参顺序,是由于形参求值顺序并非从左到右引起的。