C++11——Alias Template(化名模板)、Template template parameter(模板模板参数)

Alias Template无论是形式还是使用都非常简单,例如:

template <typename T>
using Vec=vector<T,MyAlloc<T>>;//在这里vector为STL容器,MyAlloc为自定义的分配器
......
Vec<int> v;//使用时可以传入模板参数,且可以简化书写

从上面的例子来看,Alias Template的作用就是简化书写以及可以传入模板参数,就从这一点,功能与#define和typedef相似甚至更强。将上面的例子用#define和typedef改写就可以发现差别:

#define Vec template <typename T> vector<T,MyAlloc<T>>
......
Vec<int> v;//此时相当于template <typename int> vector<int,MyAlloc<int>> v;显然无法达到和Alias Template相同的效果
typedef vector<int,MyAlloc<int>> Vec
......
Vec v;//typedef不接受参数,因此模板参数无法更改,显然也无法达到和Alias Template相同的效果

注意:Alias Template本质上也就相当于给类型起了一个别名。当该类型是一个模板类时,不能针对别名进行特化或偏特化,而只能针对原始的类型进行特化或偏特化
其实假如Alias Template只有上面用法的话,也没什么值得讲的。其真正值得我们去学习的是下面的一种用法,简单来讲就是存在一个场景,用户需要传入两个模板参数,一个是容器类型,一个是容器中的元素类型,接口在拿到这两个模板参数后可以实例化存储相应类型元素的容器对象。

class MyValueType {
public:
	MyValueType() {
		a = rand() % 3000;
	}
	friend ostream& operator<<(ostream& os, const MyValueType& str);
private:
	int a;
};
ostream& operator<<(ostream& os, const MyValueType& str)
{
	os << str.a << endl;
	return os;
}

template <typename Container,typename T>
void test_container(Container container,T elem)
{
	srand(time(NULL));
	Container<T> c;//error:Container不是一个模板类
	for(int i=0;i<30000000;i++){
		c.insert(c.end(),T());
		cout<<*(c.end()-1);
	}				
	...
}

上面的测试实例中我希望能够完成如下调用:

test_container(vector<MyValueType>(),MyValueType());//即可以向接口中传入任意容器,容器中存储任意类型

但显然 Container< T> c无法通过编译。
这里换一种方法:

template <typename Container>
void test_container(Container container)
{
	srand(time(NULL));
	Container c;
	typedef typename iterator_traits<typename Container::iterator>::value_type ValueType;//使用iterator_traits萃取容器中的元素类型
	for (int i = 0; i<3000000; i++) {
		c.insert(c.end(), ValueType());
		cout << *(c.end()-1);
	}
					
	...
}

此时可以完成一下调用:

test_container(vector<MyValueType>());
test_container(list<MyValueType>());

这样虽然算是满足了基本要求,即用户传入两个模板参数,一个是容器类型,一个是容器中的元素类型,接口在拿到这两个模板参数后可以实例化存储相应类型元素的容器对象。
但终究与我们最初设想并不相同,在上例Container c中Container包含了容器也包含了容器中元素类型, Container< T> c还是没有实现。
为此,这里引入Template template parameter——模板模板参数,即模板参数本身又是一个模板,将其引入后使用如下:

template <typename T,template<typename> class Container>//template<typename> class Container就是一个模板模板参数,其本身应该写成template<typename T> class Container,但由于前后两个T相同,就把就一个T省略掉了
class TestContainer{
private:
	Container<T> c;
public:
	TestContainer(){
		srand(time(NULL));
		for(int i=0;i<30000000;i++){
		c.insert(c.end(),T());
		cout<<*(c.end()-1);
	}		
};

上面的模板类单独编译可以通过,但执行如下调用编译会报错:

TestContainer<MyValueType,vector> c;//error:第二个模板参数无法匹配

为什么匹配不了呢,我们可以看一下vector的源码:

template <typename _Tp,typename _Alloc=std::allocator<_Tp>>
class vector:protected _Vector_base<_Tp,_Alloc>{
......
};

从上面可以看到,vector有两个模板参数,第一个是容器中元素类型,第二个是分配器。一般我们在使用时,只需要给出元素类型就可以了,分配器作为默认模板参数拿到类型后可以直接分配空间。但在这里,我们的元素类型是一个模板参数,编译器这里无法推导出元素类型后给分配器让其完成空间分配的工作(其实我觉得应该可以让编译器去完成,但至少目前没有编译器可以实现,不知道以后会不会实现)。
接下来就需要Alias Template闪亮登场了(哎,铺垫这么多,累~~),使用方式如下:

//Alias Template要放在函数体外,作为全局存在
template <typename T>
using Vec=vector<T,allocator<T>>;//显式地告诉编译器容器的第二参数是以第一参数为参数
...
TestContainer<MyValueType,Vec> c;//!!!!!!!!!!!!!!!!!!!!!

其实这一连串的骚操作现实中使用的不多,但思考分析方式确实让人脑洞打开!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值