更新时间:2022-08-25 19:53
可变参数模板是模板编程时,模板参数(template parameter)的个数可变的情形。已经支持可变参数模板的编程语言有D语言与C++(自C++11标准)。可变模板参数(variadic templates)是C++ 11新增的最强大的特性之一,它对参数进行高度泛化,它能表示0到任意个数、任意类型的参数。
C++11之前,模板(类模板与函数模板)在声明时必须有 固定数量的模板参数。C++11允许模板定义有任意类型任意数量的模板参数。
上述模板类tuple可以有任意个数的类型名(typename)作为它的模板形参(template parameter)。例如,上述模板类可以实例化具有3个类型实参(type argument)为:
也可以有0个实参,如tuple<> some_instance_name;也是可以的。如果不希望可变参数模板有0个模板实参,可以如下声明:
可变参数模板也适用于函数模板,这不仅给可变参数函数(variadic functions,如printf)提供了类型安全的附加机制(add-on),还允许类似printf的函数处理不平凡对象。例如:
省略号(...)在可变参数模板中有两种用途:
具体例子见下文。实际上,能够接受可变参数个数的参数包展开的场合,必须是能接受任意个数的逗号分隔开的表达式列表,这也就是上述四种场合。
可变参数模板经常递归使用。可变模板参数自身并不可直接用于函数或类的实现。例如,printf的C++11可变参数的替换版本实现:
这是一个递归实现的模板函数。注意这个可变参数模板实现的printf调用自身或者在args...为空时调用基本实现版本。
没有简单机制去在可变模板参数的每个单独值上迭代。几乎没有什么方式可以把参数包转为单独实参来使用。通常这靠函数重载,或者当函数可以每次捡出一个实参时用哑扩展标记(dumb expansion marker):
逗号运算符大括号封闭的初始化器列表(initializer list),这保证了严格的从左到右的求值顺序。为避免void返回类型带来的麻烦,使用逗号运算符使得每个扩展元素总是返回1。例如:
GCC尚不支持lambda表达式包含为展开的参数包,因此下述语句编译不通过:
Visual C++ 2013支持上述风格的语句。当然,这里的lambda函数不是必需的,通常的表达式即可:
如果args...包含至少一个实参,则将调用第二个版本的函数;如果参数包为空将调用第一个“终结”版的函数。可变参数模板可用于异常规范(exception specification)、基类列表(base class list)、构造函数初始化列表(constructor's initialization list)。例如:
上例中,实参列表被解包给TypeToConstruct的构造函数。std::forward
例如SomeStruct