C++新特性之Variadic Template

可变参数模板的定义

可变参数模板是至少有一个参数宝的模板,参数包则是可以接受零个或者更多模板实参的模板形参,其格式如下:

template <class ...T> class classname;

template <class ...T> void func(T ...args);

其中T为模板参数包,args为函数参数包。

可变参数模板可以用任意数量的模板参数实例化:

template <class... T> class Myclass{};
Myclass<> t0;           //T 不包含实参
Myclass<int> t1;        //T 包含一个实参,类型为int
Myclass<int,float> t2;  //T 包含两个实参,类型为int和float

//模板参数包必须是模板参数列表中的最后一个形参。
template <typename... T,typename U> struct Invalid;    //错误

可变参数函数模板可以用任意数量的函数实参调用:

template <class... T> void func(T... args);
func();        //args不包含实参
func(1);        //包含一个实参,类型为int
func(1,2.1);    //包含两个实参,类型为int和double

//与类模板不同,函数模板参数包不必是模板参数列表中的最后一个,它可以在列表早于所有能从函数实参推导的参数出现
template <class... T,class U>
void valid(U,T...);     //正确

valid(1.0,2,3,4);       //推导U为double,T为{int,int,int}

包展开

包展开的场所不同,产生的逗号分隔列表种类不同:

  1. 函数实参列表
func(&args...);         //展开成func(&E1,&E2,&E3)
func(++args...,n);      //展开成func(++E1,++E2,++E3,n)
func(n,++args);         //展开成func(n,++E1,++E2,++E3)
func(const_cast<const Args*>(&args)...);    // func(const_cast<const E1*>(&X1), const_cast<const E2*>(&X2), const_cast<const E3*>(&X3))
func(h(args...) + args...); // 展开成 func(h(E1,E2,E3) + E1, h(E1,E2,E3) + E2, h(E1,E2,E3) + E3)
  1. 有括号初始化器
Class c1(&args...);             // 调用 Class::Class(&E1, &E2, &E3)
Class c2 = Class(n, ++args...); // 调用 Class::Class(n, ++E1, ++E2, ++E3);
  1. 花括号环绕的初始化器
template <class... T> void func(T... args)
{
    const int size=sizeof...(args);
    int res[size]={args...};
}
  1. 模板实参列表
//包展开可以用于模板形参列表的任何位置,前提是模板拥有匹配展开的形参。
template <class A,class B,class... C> void func(A arg1,B arg2,C... arg3)
{
    container<A,B,C...> t1;     // 展开成 container<A,B,E1,E2,E3> 
    container<C...,A,B> t2;     // 展开成 container<E1,E2,E3,A,B> 
    container<A,C...,B> t3;      // 展开成 container<A,E1,E2,E3,B> 
}
  1. 函数形参列表
template<typename ...Ts> void f(Ts...) {}
f('a', 1);  // Ts... 展开成 void f(char, int)
f(0.1);     // Ts... 展开成 void f(double)
  1. 模板形参列表
template <class ...T> class Myclass
{
    template<T... Values> // 展开成无类型模板参数列表,例如 <int, char, int(&)[5]>
};
  1. Lambda捕获
template <class ...T>
void func(T... args){
    auto g=[&,args...]{return h(args...);}
    g();
}
  1. sizeof…运算符
  2. 基类指定符和成员初始化列表
template<class... Mixins>
class X : public Mixins... {
 public:
    X(const Mixins&... mixins) : Mixins(mixins)... { }
};

实例

#include <iostream>

using namespace std;

void print(){
    cout<<endl;
}

template <class T> void print(const T& t){
    cout<< t <<endl;
}

template <class First,class... Rest>void print(const First& first,const Rest&... rest){
    cout<<first<<",";
    print(rest);
}

int main()
{
    print();
    print(1);
    
    print(10,20);
    print(100,200,300);
    print("first",2,"third",3.14159);
}

实现C语言中的printf函数:

#include <iostream>
 
void tprintf(const char* format) // 基函数
{
    std::cout << format;
}
 
template<typename T, typename... Targs>
void tprintf(const char* format, T value, Targs... Fargs) // 递归变参数函数
{
    for ( ; *format != '\0'; format++ ) {
        if ( *format == '%' ) {
           std::cout << value;
           tprintf(format+1, Fargs...); // 递归调用
           return;
        }
        std::cout << *format;
    }
}
 
int main()
{
    tprintf("% world% %\n","Hello",'!',123);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值