C++ template高阶技巧(4)---《C++ Templates》
来源:互联网 发布:免费注册淘宝账号官网 编辑:程序博客网 时间:2024/06/05 04:19
摘要:
1)function templates不允许拥有template template parameters;
2)assignment运算符的template版本不会取代default assignment运算符;
3)可以将class template当做template parameter使用,称为template template parameters;
4)只有当采用by value方式使用字符串字面常数时候,字符串底部的array才会被转型(退化)为一个字符指针。
关键词typename
typename有两种作用,一种是放在template后面的类型参数中声明type template parameter,另一种是放在class template或者tunction template内部声明参数类型。
template <typename T>class MyClass{ typename T::SubType* ptr; ...};
以上面代码为例,如果我们不在MyClass中声明typename的话,是什么意思呢?SubType会被认为Class T的一个static成员,然后和ptr做乘法运算而已。如果声明为typename的话呢,则SubType就是class T内部定义的一个类型,从而ptr是一个指向T::SubType的指针。
下面例子是typename的两种作用在function template中的应用体现:
#include <iostream>template <typename T>void printcoll(T const& coll){ typename T::const_iterator pos; typename T::const_iterator end(coll.end()); for(pos=coll.begin();pos!=end;++pos){ std::cout<<*pos<<" "; } std::cout<<std::endl;}
.
template构件
template <int N>void printBitset(std::bitset<N> const& bs){ std::cout<<bs.template to_string<char,char_traits<char>,allocator<char> >();}
这个例子中我们在bs后面添加.template狗之间,显得有些奇怪,为什么要添加呢?这是因为如果不添加的话,编译器无法得知紧跟后面的“<”代表的是个template argument list的其实,而非一个小于符号。注意,只有当位于“.”之前的构件取决于某个template parameter时候,这种问题才会发生,上例中bs是取决于N的,一次需要添加.template构件。“.template”或者”->template”记号只在template中才能使用,而且必须紧跟与template parameter相关联的对象。
使用this->
class Base{public: void exit();};template <typename T>class Derived:public Base<T>{public: void foo(){ exit(); }};
本例中,针对模板Base<T>,编译阶段就会出错,因为定义于是Base内的exit会被编译器忽略,因此要么得到编译错误,要么就是调用的外部exit()。建议在使用与template相关的符号时候,总是以this->或者Base<T>::进行修改时。
Member Template(成员模板)
class的成员也可以是template:既可以是nested class template,也可以是member function template。
这里我们举个例子,是针对不同类型的Stack进行相互赋值的操作,进而引出成员模板的需求:
Stack<int> intStack1,intStack2;Stack<float> floatStack;...intStack1=intStack2;//OKfloatStack=intStack2;//Error,这两个Stack类型不同
针对这种情况,我们只需要将assignment运算符定义为一个template,然后我们就可以让两个“类型不同氮气元素类型可以隐式类型转换”的stack相互赋值。因此,我们的Stack需要进行如下声明:
template <typename T>class Stack{private: std::deque<T> elems;public: void push(T const&); void pop(); T top() const; bool empty() const{ return elems.empty(); } template <typename T2> Stack<T>& operator=(Stack<T2> const&);};template <typename T>template <typename T2>Stack<T>& Stack<T>::opearator=(Stack<T2> const& op2){ if((void*)this==(void*)op2){ return *this; } Stack<T2> tmp(op2); elems.clear(); while(!tmp.empty()){ elems.push_front(tmp.top()); tmp.pop(); } return *this;}Stack<int> intStack1,intStack2;Stack<float> floatStack;...floatStack=intStack1;//OK
注意,上面的template assignment运算符不会取代default assignment运算符,如果你在相同类型的stack之间赋值,编译器还是会采用default assignment运算符。
我们也可以将内部容器的类型也参数化:
template <typename T,typename CONT=std::deque<T> >class Stack{private: CONT elems;public: void push(T const&); void pop(); T top() const; bool empty() const{ return elems.empty(); } template <typename T2,typename CONT2> Stack<T,CONT>& operator=(Stack<T2,CONT2> const&);};template <typename T,typename CONT>template <typename T2,typename CONT2>Stack<T,CONT>& Stack<T,CONT>::operator=(Stack<T2,CONT2> const& op2){ if((void*)this==(void*)&op2){ return *this; } Stack<T2,CONT2> tmp(op2); elems.clear(); while(!tmp.empty()){ elems.push_front(tmp.top()); tmp.pop(); } return *this;}
Template Template Parameters(双重模板参数)
一个template parameter本身也可以是个class template,这一点非常重要。
以前为了使用其他类型的元素容器,stack class需要两次指定元素类型:一次是元素类型本身,另一种是容器类型:
Stack<int,std::vector<int> > VStack;
如果我们使用template template parameter的话,就可以只指明元素类型,无需指定容器类型,为了完成这种情况,我们需要使用template template parameters,如下:
template <typename T,template <typenam ELEM> class CONT=std::deque>class Stack{private: CONT<T> elems;public: void push(T const&); void pop(); T top() const; bool empty() const{ return elems.empty(); }};
与先前的stack相比,这儿第二个template parameter被声明为一个class template,如果我们使用template <typename ELEM> typename CONT>则会失效,因为这儿CONT是一个class类型,因此必须使用class来加以声明。
Template Template Argument的匹配
template template argument不但必须是个template,而且其必须严格匹配它所替换的template template parameter的参数。Template template argument的默认值不被考虑,因此如果不给出所拥有的默认自变量值时后,编译器会认为匹配失败。
针对上面的template template parameters,如果我们使用以下代码替代:
template <typename T,template <typename> class CONT=std::deque>class Stack{ ...};template <typename T,template <typename> class CONT>void Stack<T,CONT>::push(T const& elem){ elems.push_back(elem);}
编译器会报错:默认值std::deque不符合template template parameter CONT的要求。问题在于:标准库中的std::deque template要求不知一个参数,第二个参数是配置器(allocator),虽然有默认值,但它被用来匹配CONT的参数时候,其默认值被编译器强行忽略了。
解决方法是可以重写class声明语句,使得CONT参数要求一个“带两个参数”的容器:
template <typename T,template <typename ELEM,typename ALLOC=std::allocator<ELEM> > class CONT=std::deque>class Stack{private: CONT<T> elems; ...};
零值初始化
针对C++中的内建类型(int、double、pointer type等等)来说,并没有一个default构造函数,使它们初始化为有意义的值,因此我们可以在声明内建类型的时候,明确调用其default构造函数,使得其值为“0”,如:
template <typename T>void foo{ T x=T();}
class template的各个成员,器类型有可能被参数化,为保证初始化这样的成员,必须定义一个构造构造函数,在其成员出事列中对每个成员进行初始化:
template <typename T>class MyClass{private: T x;public: //这样可以保证及时T为内建类型时,x也可以被初始化 MyClass():x(){ } ...};
以字符串字面常数作为Function Template Argument
以by reference传递方式将字符串字面常数传递给function template parameters时候,有可能遇上奇怪的错误:
#include <string>template <typename T>inline T const& max(T const&a,T const&b){ return a<b?b:a;}int main(){ std::string s; max("apple","peach");//OK max("apple","tomato");//Error,类型不同 max("apple",s);//Error,类型不同 return 0;}
换句话说“apple”和“peach”的array类型都是char const[6],而“tomato”是char const[7],上述调用只哟偶第一个合法,因为两个参数具有相同的类型,如果你使用by value传递,就可以传递不同类型的字符串字面常数,即通过退化的方式解决,其对应的array大小不同:
#include <string>template <typename T>inline T max(T a,T b){ return a<b?b:a;}int main(){ std::string s; ::max("apple","peach");//OK ::max("apple","tomato");//OK ::max("apple",s);//Error,类型不同}
template <typename T,int N,int M>T const* max(T const(&a)[N],T const(&b)[M]){ return a<b?b:a'}
强迫使用者进行显示转换,注意这也并不会解决string和const char*的问题。
- C++ template高阶技巧(4)---《C++ Templates》
- c++Templates学习笔记(一)
- c++Templates学习笔记(二)
- c++Templates学习笔记(三)
- C++template
- C template
- C++Template
- C++templates简单基础--Function Templates
- Template设计模式(C++)
- C++(15):模板(Template)
- Design Pattern - Template Method(C#)
- C++template(模板)的使用
- list c++template
- Queue-C++template
- Stack-c++template
- C++Template之Priority_queue
- [C++] Template练习
- eclipse-c-template
- [日推荐] 『无忧育儿说』养育孩子就是这么简单!
- lua lib 的编译
- 对double类型中存在-0.0的数据检验
- 安卓软键盘的处理
- 总结
- C++ template高阶技巧(4)---《C++ Templates》
- 【swift】关于po命令不显示问题 error: <EXPR>:3:1: error: use of unresolved identifier
- ES6 Arrow functions
- css元素隐藏各种方式原理及display:none和visibility:hidden
- 阿里前端笔试题
- How To Set HANA ODBC Connection Properties
- C#自定义RSA加密解密及RSA签名和验证封装类
- Merge into的注意点之ORA-30926: 无法在源表中获得一组稳定的行?
- 【搜狗投稿】【测试工具】Fiddler实践的一些小心得