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…,其作用是计算参数包中的参数个数。

时间: 2024-11-08 20:28:23

C++11变长模板解析(深入理解C++11)的相关文章

C++11 变长参数的宏定义以及__VA_ARGS__

[1]变长参数的宏定义以及__VA_ARGS__ 在C99标准中,我们就已经可以使用变长参数的宏定义. 变长参数的宏定义是个神马?就是在宏定义的参数列表中最后一个参数为省略号. 而现在C++ 11中,使用预定义宏__VA_ARGS__可以在宏定义的实现部分替换省略号所代表的字符串. 原书示例: #include <stdio.h> #define LOG(...) { \ fprintf(stderr, "%s: Line %d:\t", __FILE__, __LINE_

C++11 变长模版和完美转发实例代码

#include <memory>#include <iostream>#include <vector>#include <stdarg.h>using namespace std; struct A{        A()        {        }        A(const A& a)        {            cout << "Copy Constructed " << _

模板解析变量理解

Discuz! 的模板采用近似 PHP 表达式的语法,支持的元素如下: <!--{ ... }--> 逻辑元素包围符,该符号用于包含条件和循环元素 条件判断 <!--{if expr1}--> statement1 <!--{elseif expr2}--> statement2 <!--{else}--> statement3 <!--{/if}--> 这是一个典型的条件模板,当条件 expr1 为真时,显示模板 statement1 内容,否

C++11的模板新特性-变长参数的模板

这个特性很赞,直接给例子吧,假如我要设计一个类,CachedFetcher内部可能使用std::map也可能使用std::unordered_map,也可能是其它的map,怎么设计呢?没有C++11变长模板之前这很费劲.. 因为map的模板参数可不是只有key,value两个啊,还有一些有默认参数的template参数... ? ? template<typename _Key, typename _Value, template<class _Kty, class _Ty, typename

介绍C++11标准的变长参数模板

目前大部分主流编译器的最新版本均支持了C++11标准(官方名为ISO/IEC14882:2011)大部分的语法特性,其中比较难理解的新语法特性可能要属变长参数模板(variadic template)了.下面先介绍一下这个语法特性在C++11标准中的描述. 14.5.3 变长参数模板(Variadic templates) 1.一个模板形参包(template parameter pack)是一个接受零个或多个模板实参的模板形参.[例: template<class ... Types> st

《深入理解C++11》要点总结

3.1 继承构造函数 通过using关键字可以继承父类的构造函数.也可以通过显式定义构造函数来阻止继承. 3.2 委派构造函数,减少构造函数的书写 class Info { public: Info() { InitReset(); } Info(int i) : Info() { type = i; } //通过调用无参构造函数,可以减少构造函数内容的重写 Info(char e) : Info() { name = e; } //委派构造函数和初始化列表不能同时存在,使用委派构造函数后,初始

Java语法糖初探(三)--变长参数

变长参数概念 在Java5 中提供了变长参数(varargs),也就是在方法定义中可以使用个数不确定的参数,对于同一方法可以使用不同个数的参数调用.形如 function(T -args).但是需要明确的一点是,java方法的变长参数只是语法糖,其本质上还是将变长的实际参数 varargs 包装为一个数组. 看下面的例子: 12345678910111213 public class VariVargs { public static void main(String []args) { tes

C++17尝鲜:变长using声明

using 声明 先来看 using 声明在类中的应用: 代码1 #include <iostream> using namespace std; struct A { void f(int) {cout << "A::f(int)" << endl;} }; struct S : A { }; int main() { S s; s.f(1); // A::f(int) } 类 S 继承了类 A 的成员函数 f,所以类 S 的实例 s 调用 f 输

C++11 新特性之 变长参数模板

template <typename ... ARGS> void fun(ARGS ... args) 首先明确几个概念 1,模板参数包(template parameter pack):它指模板参数位置上的变长参数,例如上面例子中的ARGS 2,函数参数包(function parameter pack):它指函数参数位置上的变长参数,例如上面例子中的args 一般情况下 参数包必须在最后面,例如: template <typename T, typename ... Args>