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

编程入门 行业动态 更新时间:2024-10-14 20:21:12

C++11——Alias Template(化名<a href=https://www.elefans.com/category/jswz/34/1770549.html style=模板)、Template template parameter(模板模板参数)"/>

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;//!!!!!!!!!!!!!!!!!!!!!

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

更多推荐

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

本文发布于:2024-02-10 22:24:21,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1677624.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:模板   化名   参数   Alias   Template

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!