C++11变长模板解析(深入理解C++11)

参考自:深入理解C++11

变长模版:

      变长函数和变长的模版参数

       变长函数:

       

double sum(int n, ...)//求n个double数据之和

{

    double sum = 0;

    va_list args;//接受输入数据的数据结构,需声明stdarg.h,

    va_start(args, n); //初始化数据

    while (n>0)

    {

        sum += va_arg(args, double); //将args中的数据一一取出,每隔sizeof(double)取一次数,再求和

        --n;

    }

    va_end(args);

    return sum;

}

         变长的模版参数:

        

 pair<int, double> PairNum

    std::tuple<>double, char, int, std::string> collections

变长模版:模版参数包函数参数包

         模版参数包:

         变长类模版:

                   template<typename...Elements> class tuple;

        在标识符Elements之前使用了省略号…来表示该参数是变长的。Elements被称作三一个“模版参数包”。这样tuple 就可以接受任意多个参数作为模版参数。其实例化的tuple模版类:

        tuple<int ,char,double>

    编译器则可以将多个模版参数打包成大哥的模版参数包Elements,即Elements在进行模版推导的时候,就是一个包含int,char,double三种类型类型集合。

        也可以声明非类型的模版参数包,如:

        template<int …A>classNonTypeVariadicTemplate{}

        NonTypeVariadicTemplate<1,2,3>ntvt;

    就是定义了个:

    template<int,int,int>class NonTypeVariadicTemplate{}

        NonTypeVariadicTemplate<1,2,3>ntvt;

 

一个模版参数包在模版推导的时候会被认为是模版的单个参数。为了使用模版参数包,我们总是需要将其解包(Unpack)。在C++11中,这通常需要通过一个名为包扩展的表达式来完成:

         template <typename …A>classTemplate : private B<A…>{};

         式中的表达式A…就是一个包扩展。这样参数包会在包扩展的位置展开为多个参数。如:

         template<typename T1, typename T2>class B{};

template<typename ...A>class Template :private B<A...>{};

Template<X, Y> xy;

这样,我们为类模版声明了一个参数包A,而使用参数包A…则是在Template的私有基类B<A…>中,那么最后一个表达式就声明了一个基类为B<X,Y>的模版类Template<X,Y>的对象xy。基类B总是接受两个参数,如果参数包的参数个数大于两个,我们在进行模版推导的时候就会发生错误。

事实上,C++11就给出了解决的办法。实现tuple模版的方式给出了一种使用模版参数包的答案。

    template<typename...Elements>class tuple ;//变长模版声明

    //递归的偏特化定义

template<typename Head, typename ... Tail>class tuple<Head,Tail...> :private tuple < Tail... > { Head head; };

template <> class tuple<> {};//边界条件

 

如我们实例化tuple<double,int,char,float>,则我们需要构造tuple<int,char,float>,然后将设置head为double型。依次构造tuple<char,float>和设置int head,tuple<float>,char head,tuple<> float head;这样就完成了实例化。

template<long...nums> struct Multiply;


 

template<long first,long ... last>

struct Multiply<first,last...>

{

            static const long val = first*Multiply<last...>::val;

};

template<> struct Multiply < > { static const long val = 1; };

 

         函数参数包:

       template<typename...T> void f(T...args);

    T为变长模板参数,args则是对应于这些变长类型的数据,即函数参数包。C++11中,要去函数参数包必须唯一而且是函数的最后一个参数(模板参数包没有这样的要求)。

void Printf(const char *s)

{

    while (*s)

    {

        if (*s == '%'&&*++s != '%')

        {

            throw runtime_error("invalid formatstring: missing arguments");

        }

        cout << *s++;

    }

}





template<typename T,typename...Args>

void Printf(const char * s, T value, Args... args)

{

    while (*s)

    {

        if (*s=='%'&&*++s!='%')

        {

            cout << value;

            return Printf(++s, args...);

        }

        cout << *s++;

    }

    throw runtime_error("extraarguments provided to Printf");

}

int main()

{

    Printf("hello %s\n", std::string("world"));

    return 0;

}

相比于变长函数,变长函数模板不会丢弃参数的类型信息。因此重载的cout总是可以将具有类型的变量正确的打印出来。这就是变长模板函数强于变长函数的地方。

 

C++11定义了七种参数包可以展开的位置:

1. 表达式

2.      初始化列表

3.      基类描述列表

4.      类成员初始化列表

5.      模板参数列表

6.      通用属性列表

7.      Lambda函数的捕捉列表

如果我们生命Arg为参数包,那么可以使用Arg&&…这样的包扩展表达式,其解包后等价于Arg1&&,…,Argn&&(Arg1为包中的第一个参数,Argn为包中的第n个参数)。

        

1.      template<typename…A>classT:private B<A>…{};

2.      template<typename…A>classT:private B<A…>{};

同样实例化T<X,Y>;

1解包后为classT<X,Y>:private B<X>,private B<Y>{};

2解包后为classT<X,Y>:private B<X, Y>{};

 

操作符sizeof…,其作用是计算参数包中的参数个数

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隨意的風

如果你觉得有帮助,期待你的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值