内容:技巧性基础知识
关键字:typename .template this-> 模板的模板参数 零初始化 字符串的模板实参
具体内容描述
1. 对模板使用typename
场景:
template <typename T>
class Test{
typename T::SubType *ptr; //使用模板参数类型里面定义的类型
...............
}
这里需要增加typename,需要标记告诉编译器这个是声明一个模板参数类型T里面的SubType类型的指针,指明T::SubType是一个类型
如果不指定typename,编译器认为是T里面的一个静态成员
2. 使用模板参数时附带.tmpelate关键字
场景
template <tint N>
void printBitset (std::bitset<N> const &bs)
{
std::cout<<bs.template to_string<char, char_traits<char>,allocator<char> > (); //这里在bs后面增加.template
}
这里和上面typename类似也是告诉编译器这里要对to_string模板函数进行处理,to_string后面紧跟的<不是小于符号是模板参数列表的开始标示
我们可以做一个比较,bs里面的to_string函数分为普通函数和模板函数来对比
bs.to_string()
bs.to_string<char>()
在使用to_string函数时不告诉编译器这个to_string函数是一个模板函数,那么紧跟函数后面的<将被认为是小于符号
扩展:可以扩展到使用一个模板参数T里面的一个模板函数需要增加::template,是一个指针时需要增加->template
3. 在模板类中使用this->
场景
template<typename T>
class Base{
void exit(){};
'}
template<typename T>
class Test : public Base<T>{
vodi print(){
exit(); //调用全局的exit函数,如果没有全局的将编译错误
this->exit(); //调用基类中的exit函数
}
}
在模板类中如果基础的基类也是一个模板类,在继承类中使用基类定义的函数需要显示指定this->也可以用名字空间标示Base<T>::exit()
4. 模板的模板参数
模板的模板参数就是将模板本身作为另一个模板的参数
典型的使用场景
在STL容器中的类型,容器可以变,容器中的参数也可以变(这里只给出声明和使用)
template <typename T, typename CONT=std::vector>
class Stack{.........}
使用Stack<int > Test; 使用默认容器。
如果换容器会是怎样?
Stack<int, std::deque<int> > Test 这里需要显示的指明
那就定义一个模板的模板参数来去掉这个显示的指明
template<typename T, template <typename ELEM> class CONT=std::vector>
class Stack{CONT<T> val; ........}
使用Stack<int, std::deque> Test,这里会完成自动推演出来-------------函数模板没有模板的模板参数这回事!!!!!!!!
注意:i 模板的模板参数中如果ELEM没有被使用可以不用显示写出来
ii 模板的模板参数需要精确的实参匹配,所以最新的Stack的声明为
template <typename T, template <typename ELEM, typename ALLOC=std::allocator> >class CONT=std::vector>
class Stack{.....}
5 零初始化
零初始化时指声明的一个命令都能够被正确初始化,比如一个内置类型int,这声明后的指是不确定的必须要显性的初始化赋值才行。
这个问题的模板中可以得到解决,看下面的例子
template<typename T>
vod fun(){
T x = T(); //这里可以做到声明和初始化一次解决,这个主要是针对内置类型而言
};
6 字符串作为函数模板的实参
我们在声明一个函数时对函数的参数会有值的传递或引用的传递(考虑到演示就不说指针的方式)
template<typename T>
T max(T a, T b) //版本一,传值方式
T const& max(T const&a, T const &b); //版本二,引用方式
{return a< b > b:a;}; //这里是函数实体
max("111","222"); //两个版本都没问题
max("1111","222"); //版本二编译不通过---------这里的参数和上面的不同只有参数的长度不同,问题也就是出在字符串参数的长度上
模板的引用方式,对字符串演绎为字符数组,长度为3和长度为4的数组对模板来说是不同类型---称为decay,而值引用都是指针char *
针对这个问题给出的建议:
1.使用非引用函数模板,但可能会导致无用拷贝
2. 重载引用版本和非引用版本,可能会参数二义性
3. 重载数组类型
template <typename T, int N, int M>
T const * mac(T const(&a)[N], T const(&b)[M])
4. 对具体类型进行重载,或者要求使用显示类型转换处理