可变参数模板(C++11)

可变模版参数(variadic templates)

是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数、任意类型的参数。

模板参数包

template<typename... A> class Car;  
//typename...就表示一个模板参数包。可以这么来实例化模板:
Car<int, char> car; 

包扩展

template<typename... a> class Car {};
template<typename... A> class BMW : public Car<A...> { };
BMW<int, char> car;
// A...称之为包扩展(pack extension),包扩展是可以传递的。

特性

template <class... T>
void f(T... args)
{    
    cout << sizeof...(args) << endl; //打印变参的个数
}

f();        //0
f(1, 2);    //2
f(1, 2.5, "");    //3

可变参数模板函数展开参数包

递归函数方式展开

//递归终止函数   特化的模板函数
void print() {
	cout << "empty" << endl;
}
//展开函数
template <class T, class... Args>
void print(T head, Args... rest) {
	cout << "parameter " << head << endl;
	print(rest...);
}

//sum例子
template<typename T>
T sum(T t)
{
    return t;
}
template<typename T, typename ... Types>
T sum (T first, Types ... rest)
{
    return first + sum<T>(rest...);
}

逗号表达式展开
递归函数展开参数包是一种标准做法,也比较好理解,但也有一个缺点,就是必须要一个重载的递归终止函数,即必须要有一个同名的终止函数来终止递归,这样可能会感觉稍有不便。有没有一种更简单的方式呢?其实还有一种方法可以不通过递归方式来展开参数包,这种方式需要借助逗号表达式和初始化列表。比如前面print的例子可以改成这样:

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

template <class ...Args>
void expand(Args... args){
   int arr[] = {(print(args), 0)...};
}

expand(1,2,3,4);
//用到数组的初始化列表,这个数组的目的纯粹是为了在数组构造的过程展开参数包。
//{(printarg(args), 0)...}将会展开成((printarg(arg1),0), (printarg(arg2),0), (printarg(arg3),0),  etc... ),
//最终会创建一个元素值都为0的数组int arr[sizeof...(Args)]。printarg便会处理参数包中每一个参数。


支持lambda表达式
template<class F, class... Args>void expand(const F& f, Args&&...args) {//这里用到了完美转发
  initializer_list<int>{(f(std::forward< Args>(args)),0)...};
}
expand([](int i){cout<<i<<endl;}, 1,2,3);

可变模版参数类展开参数包

可变参数模板类的参数包展开需要通过模板特化和继承方式去展开。

模版偏特化和递归方式来展开参数包

//前向声明(限定了参数至少是1个)
template<typename... Args>
struct Sum;

//基本定义
template<typename First, typename... Rest>
struct Sum<First, Rest...>{
    enum { value = Sum<First>::value + Sum<Rest...>::value };
};

//递归终止
template<typename Last>
struct Sum<Last>{
    enum { value = sizeof (Last) };
};


不带声明的版本(限定了参数至少是1个)
template<typename First, typename... Rest>
struct Sum {
	enum { value = Sum<First>::value + Sum<Rest...>::value };
};

template<typename Last>
struct Sum<Last> {
	enum { value = sizeof(Last) };
};

继承方式展开参数包

//整型序列的定义
template<int...>
struct IndexSeq {};

//继承方式,开始展开参数包
template<int N, int... Indexes>
struct MakeIndexes : MakeIndexes<N - 1, N - 1, Indexes...> {};

// 模板特化,终止展开参数包的条件
template<int... Indexes>
struct MakeIndexes<0, Indexes...> {
	typedef IndexSeq<Indexes...> type;
};


MakeIndexes<3> b;
MakeIndexes<6>::type c;
cout << typeid(b).name() << endl;//struct IndexSeq<0,1,2>
cout << typeid(c).name() << endl;//struct IndexSeq<0, 1, 2, 3, 4, 5>


/*展开过程
MakeIndexes<3> : MakeIndexes<2, 2>{}

MakeIndexes<2, 2> : MakeIndexes<1, 1, 2>{}

MakeIndexes<1, 1, 2> : MakeIndexes<0, 0, 1, 2>

MakeIndexes<0, 0, 1, 2>{
	typedef IndexSeq<0, 1, 2> type;
}
*/

可变参数模版消除重复代码
消除重复代码,去掉参数个数的限制,代码很简洁

template<typename…  Args>
T* Instance(Args&&… args)
{
    return new T(std::forward<Args>(args));
}
A* pa = Instance<A>(1);
B* pb = Instance<B>(1,2);

参考 https://www.cnblogs.com/qicosmos/p/4325949.html

  • 15
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值