您的位置:首页 > 编程语言 > C语言/C++

C++11 可变模板参数

2017-07-06 11:07 441 查看

前言

C++11 增强了模板功能,在C++11之前,类模板和函数只能含有固定数量的模板参数,现在C++11中的新特性可变参数模板允许模板定义中包含0到任意个模板参数。可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面加上省略号“...”。其中的省略号的作用是:

(1)声明一个参数包,这个参数包中可以包含0到人一个模板参数

(2)在模板定义的右边,可以将参数包展开成一个一个独立的参数

1. 可变参数模板

一个可变参数模板的定义是这样的

template<class... T> void template_func(T... args)
{
cout << sizeof...(args) << endl;
}

template_func(1); //输出结果1
template_func(1, 2, 3); //输出结果3
template_func(1, 2, ""); //输出结果3从上面的例子可以看到,参数包可以容乃0到N个模板参数,这几个参数的类型可以任意的,在没有进行传参的时候,那么输出的结果就是0了。如果需要用参数包的参数,则一定要将参数包打开。有两种展开参数包的方法:
(1)通过递归的模板函数来实现参数包展开

(2)通过都好表达式和初始化列表方式展开参数包

1.1 递归函数方式展开参数包

通过递归函数展开参数包,需要提供一个参数包展开的函数和一个递归终止的函数,递归终止的函数正是用来终止递归的。

//递归展开参数包
template<class Q, class... T> void template_func(Q head, T... args)
{
cout << "parameters:" << head << endl;
template_func(args...); //递归展开参数包
}

//递归的终止函数
void template_func()
{
cout << "end" << endl;
}

template_func(1, 2, 3, 4);上面有两个函数,一个是递归函数一个是递归终止函数,参数包args...在展开自己的过程中递归调用自己,没吊用一次参数包中的参数就会减少一个,知道所有的参数都展开为止,当没有参数的之后,就调用递归终止函数结束。
也可将上面的非模板函数写成模板函数

//递归展开参数包
template<class K, class... T> void template_func1(K head, T ...args)
{
cout << "parameters:" << head << endl;
template_func1(args...); //递归展开参数包
}

//递归的终止函数
template<class T> void template_func1(T t)
{
cout << t << endl;
}

template_func1(1,2,3,4);

1.2 逗号表达式和初始化列表方式展开参数包

递归函数展开参数包是一种标准做法,也比较好理解,但也存在一个缺点,就是必须要有一个重载的递归终止函数。使用逗号表达式和初始化列表就可以避免使用递归终止函数。

//展开参数包
template<class... T> void template_func1(T ...args)
{
int array[] = {(my_print(args), 0)...};
}

template<class T> void my_print(T t)
{
cout << t << endl;
}

template_func1(1,2,3,4);

2. 可变参数模板消除重复代码

可变参数模板的一个特性是参数包中的模板参数可以是任意数量的和任意类型的,因此,可以以一种更加返回的方式去处理一些问题。

下面是原始的创建对象工厂函数

template<typename T> T* Instance()
{
return new T();
}

template<typename T,typename T0> T* Instance(T0 arg0)
{
return new T(arg0);
}

template<typename T, typename T0, typename T1> T* Instance(T0 arg0, T1 arg1)
{
return new T(arg0, arg1);
}

template<typename T, typename T0, typename T1, typename T2> T* Instance(T0 arg0, T1 arg1, T2 arg2)
{
return new T(arg0, arg1, arg2);
}

struct A
{
A(int a)
{}
};

struct B
{
B(int a, int b)
{}
};

A* p_a = Instance<A>(1);
B* p_b = Instance<B>(1, 2);修改之后
struct A
{
A(int a)
{}
};

struct B
{
B(int a, int b)
{}
};

template<typename T, typename... args> T* Instance(args... arg)
{
return new T(arg...);
}

A* p_a = Instance<A>(1);
B* p_b = Instance<B>(1, 2);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: