变长模板
变参模板
变参模板实列
可以将模板参数定义成能够接受任意多个模板参数的情况。这一类模板被称为变参模板,可以通过调用下面代码中的 print()函数来打印一组数量和类型都不确定的参数:
1 | void print() {} |
当传入一个或多个参数时会调用模板函数,这里通过将第一个参数单独声明,就可以先打印第一个参数,然后再递归的调用print()
,args被称为剩余参数,是一个函数参数包Types ...args
,使用了模板参数包定义类型Types,为了结束递归,重载了不接受参数的非模板函数 print()
变参和非变参模板的重载
上述print还可以通过如下方法实现:
1 | template <typename T> |
当两个函数模板的区别只在于尾部的参数包的时候,会优先选择没有尾部参数包的那一个函数模板
sizeof… 运算符
C++11 为变参模板引入了一种新的 sizeof 运算符:sizeof...
它会被扩展成参数包中所包含的参数数目,sizeof...
既可以用于模板参数包也可以同于函数参数包,且二者效果相同(返回值相同),均返回当前参数包参数的个数
这样可能会让你觉得,可以不使用为了结束递归而重载的不接受参数的非模板函数 print(), 只要在没有参数的时候不去调用任何函数就可以了:
1 | template<typename T, typename… Types> |
这种方法是错误的,,因为通常函数模板中 if 语句的两个分支都会被实例化。是否使用被实例化出来的代码是在运行期间(run-time)决定的,而是否实例化代码是在编译期间 (compile-time)决定的。因此如果在只有一个参数的时候调用 print()函数模板,虽然args...
为空,if 语句中的 print(args...)
也依然会被实例化,但此时没有定义不接受参数的 print()函数, 因此会报错
变参下标
下面的函数通过一组变参下标来访问第一个参数中相应的元素:
1 | template <typename C ,typename ...Idx> |
也可以将非类型模板参数声明成参数包
1 | template<std::size_t… Idx, typenam> |