C++0x尝鲜:Variadic Function Templates(带变长参数的函数模板)

来源:互联网 发布:北京现代软件学院 图片 编辑:程序博客网 时间:2024/04/30 14:08

关于变长参数模板(Variadic Templates)

在C++0x之前,模板(包括类模板和函数模板)参数的个数和类型是固定不变的,而且都必须在定义时预先确定。在C++0x中,这一点得到了改善,模板(无论类模板还是函数模板)将具有指定任意个数任意类型参数的能力,这就是所谓的变长参数模板(Variadic Templates)。

下面我们就用代码说明带变长参数的函数模板。

C++代码

#include <iostream>using namespace std;template<typename T>void output(T&& value){    cout << value << endl;}template<typename First, typename... Rest>void output(First&& first, Rest&&... rest){    cout << first << ",";    output(forward<Rest>(rest)...);}template<typename T>T sum(T&& value){    return value;}template<typename First, typename Second, typename... Rest>First sum(First&& first, Second&& second, Rest&&... rest){    return sum(first + second, forward<Rest>(rest)...);}int main(){    double d = 2.3;    output(42,"hello",d,'a');    output("hello",d,'a');    output(d,'a');    output('a');    output(sum(1), sum(1, 2), sum(1, 2, 3));    return 0;}//42,hello,2.3,a//hello,2.3,a//2.3,a//a//1,3,6
代码说明
  1. 代码中的 output 与 sum 是两个可接受变长参数的函数模板。
    output 函数接受一个及以上的参数,函数功能为输出各个参数的值。
    sum 函数同样接受一个及以上的参数,函数功能为计算各个参数的和。
  2. 代码中output 函数有两个版本。
  3. 参数只有一个时调用4~8行所定义的非递归版本,
    此版本参数个数固定,C++11之前即已合法。
  4. 参数有两个及以上时调用9~14行所定义的递归版本,
    此版本参数个数可变,依赖C++11新增的语言特性。
  5. 代码第9行模板参数列表中的 typename... Rest 部分被称作模板参数包
    实际调用时模板参数包 Rest  内将存放可变长部分各参数(第1个参数first之后的所有参数)的类型
    如第30行用 output(42,"hello",d,'a'); 调用时,Rest 的内容为(char*, double&, char)
  6. 代码第10行函数参数列表中的 Rest&&... rest 部分被称作函数参数包
    实际调用时函数参数包 rest  内将存放可变长部分各参数(第1个参数first之后的所有参数)的值
    如第30行用 output(42,"hello",d,'a'); 调用时,rest 的内容为("hello",d,'a')
  7. 代码第13行中的...被称为解包运算符,
    实际调用时解包运算符将把它之前的表达式(即forward<Rest>(rest))作为模板来展开
    模板参数包Rest 以及函数参数包rest,展开之后所生成的各表达式将用逗号连接,
    如第30行用 output(42,"hello",d,'a'); 调用时,forward<Rest>(rest)... 将被展开为
    forward<char*>("hello"), forward<double&>(d), forward<char>('a')
  8. 由以上分析可知
    递归版本的output函数输出第一个参数first的值以及逗号之后用剩余参数递归调用自身,
    非递归版本的output函数则只输出唯一一个参数value的值,不会输出逗号。
  9. 第30行用 output(42,"hello",d,'a'); 调用时模拟运行结果如下
    output(42,"hello",d,'a')
    = 输出"42,“ 之后调用 output(forward<char*>("hello"), forward<double&>(d), forward<char>('a'))
    = 输出"42,“ 之后调用 output("hello", d, 'a')
    = 输出"42,hello,“ 之后调用 output(forward<double&>(d), forward<char>('a'))
    = 输出"42,hello,“ 之后调用 output(d, 'a')
    = 输出"42,hello,2.3,“ 之后调用 output(forward<char>('a'))
    = 输出"42,hello,2.3,“ 之后调用 output('a')
    = 输出"42,hello,2.3,a“
    注意最后一步调用非递归版本,因而没有输出逗号。
  10. 与output 函数相类似,sum 函数同样有两个版本
    重复以上分析可知
    递归版本的sum 函数计算前两个参数first及second的和之后使用计算结果与剩余参数递归调用自身,
    非递归版本的sum 函数则返回唯一一个参数value的值。
  11. 第34行用 sum(1,2,3); 调用时模拟运行结果如下
    sum(1,2,3)
    = sum(1+2, forward<int>(3))
    = sum(1+2, 3)
    = sum(1+2+3)
    = 1+2+3
    = 6

原创粉丝点击