可变参数模板是模板编程时,模板参数(template parameter)的个数可变的情形。已经支持可变参数模板的编程语言有D语言与C++(自C++11标准)。可变模板参数(variadic templates)是C++ 11新增的最强大的特性之一,它对参数进行高度泛化,它能表示0到任意个数、任意类型的参数。
C++11声明C++11之前,模板(类模板与函数模板)在声明时必须有 固定数量的模板参数。C++11允许模板定义有任意类型任意数量的模板参数。
template class tuple;上述模板类tuple可以有任意个数的类型名(typename)作为它的模板形参(template parameter)。例如,上述模板类可以实例化具有3个类型实参(type argument)为:
tuple some_instance_name;也可以有0个实参,如tuple some_instance_name;也是可以的。如果不希望可变参数模板有0个模板实参,可以如下声明:
template class tuple;可变参数模板也适用于函数模板,这不仅给可变参数函数(variadic functions,如printf)提供了类型安全的附加机制(add-on),还允许类似printf的函数处理不平凡对象。例如:
template void printf(const std::string &str_format, Params... parameters);使用省略号(...)在可变参数模板中有两种用途:
省略号出现形参名字左侧,声明了一个参数包(parameter pack)。使用这个参数包,可以绑定0个或多个模板实参给这个可变模板形参参数包。参数包也可以用于非类型的模板参数。
省略号出现包含参数包的表达式的右侧,则把这个参数包解开为一组实参,使得在省略号前的整个表达式使用每个被解开的实参完成求值,所有表达式求值结果被逗号分开。注意这里的逗号不是作为逗号运算符,而是用作:
被逗号分隔开的一组函数调用实参列表;(该函数必须是可变参数函数,而不能是固定参数个数的函数)
被逗号分隔开的一组初始化器列表(initializer list);
被逗号分隔开的一组基类列表(base class list)与构造函数初始化列表(constructor's initialization list);
被逗号分隔开的一组函数的可抛出的异常规范(exception specification)的声明列表。
具体例子见下文。实际上,能够接受可变参数个数的参数包展开的场合,必须是能接受任意个数的逗号分隔开的表达式列表,这也就是上述四种场合。1
可变参数模板经常递归使用。可变模板参数自身并不可直接用于函数或类的实现。例如,printf的C++11可变参数的替换版本实现:
void printf(const char *s){ while (*s) { if (*s == '%') { if (*(s + 1) == '%') { ++s; } else { throw std::runtime_error("invalid format string: missing arguments"); } } std::cout