一:关键字typename
typename的另一个用法: 告诉编译器把一个特殊的名字理解为类型。
如下:
template <typename T>
class MyClass {
typename T::SubType * ptr;
};
template<typename T>
class MyClass {
T::SubType * ptr;
};
没有typename的版本可以有另一种理解: T类中的SubType成员 与 ptr 相乘。
这里用typename 声明 Subtype是一种类型而不是变量。
二: .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 编译器将不知道 后面的<符号意义 (模板或者是小于号)
三:使用this->
template <typename T>
class Base {
public:
void exit();
};
template <typename T>
class Derived : Base<T> {
public:
void foo() {
exit();//这里会调用外部的exit()或者出现错误
}
};
通过显式使用this-> 或者 Base<T>::来避免不确定性。
四:成员模板
之前说过的不同类型的栈不能相互赋值因为缺省的赋值函数要求两边的类型一样。
既然这样我们可以强行定义模板的赋值运算符实现不同元素类型模板之间的赋值。
例如:
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>::operator = (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;
};
五:模板的模板参数
例如:
template<typename T, template <typename 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();
}
};
注:
1.这里的class是为了定义一个类 不能用typename替换
2.函数模板不支持模板的模板参数
六:零初始化
模板中类型初始化
template <typename T>
void foo()
{
T x = T();
}
template <typename T>
class MyClass {
private:
T x;
public:
MyClass() : x() {
}
};
七:使用字符串作为函数模板的实参
字符串传递给函数模板的引用参数的一些问题,如下:
#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
}
一个是const char[6]类型 一个是const char[7]类型
如果是非引用参数,则可以使用长度不同的字符串作为max()的参数。
因为对于非引用参数,在实参演绎的过程中,会出现数组到指针的转换。