- 声明template参数是,template< class >和template< typename >是等价的。
但有例外:
template<typename C>
// const C& c 不需要加typename
void f(const C& c){
// 嵌套从属类型名称,我们需要放置关键字typename
// 为了告诉c++编译器C::const_iterator是个类型,缺省的话会被定为为非类型
typename C::const_iterator iter(c.begin());
// 太长的话也可以这么写
typedef typename C::const_iterator Iter;
Iter iter(c.begin());
...
}
- 模板类名称使用,模板全特化与偏特化
class Ta{
public:
void show(const std::string& msg);
...
};
class Tb{
public:
void show(const std::string& msg);
...
};
class Tc{
public:
//没有show()函数
...
};
template<typename T>
class MsgShow{
public:
void doShow(const std::string& msg){
T t;
t.show(msg);
}
};
//全特化版
template<>
class MsgShow<Tc>{
public:
...
};
template<typename T>
class MsgShowMore : public MsgShow<T>{
public:
void doShowMore(const std::string& msg){
doShow(msg); // 无法通过编译,因为此时编译器不知道T是个template参数,不知道是啥东西
}
}
//为了通过编译,我们要让编译器不进入模板基类观察行为
//1.
template<typename T>
class MsgShowMore : public MsgShow<T>{
public:
void doShowMore(const std::string& msg){
this->doShow(msg); //通过编译
}
}
//2.
template<typename T>
class MsgShowMore : public MsgShow<T>{
public:
using MsgShow<T>::doShow;
void doShowMore(const std::string& msg){
doShow(msg); //通过编译
}
}
//3.
template<typename T>
class MsgShowMore : public MsgShow<T>{
public:
void doShowMore(const std::string& msg){
MsgShow<T>::doShow(msg); //通过编译
}
}
//特化版本没有doShow()
MsgShowMore<Tc> cmsg;
std::string msg;
...
cmsg.doShowMore(msa); //错误,因为Tc中没有doShow()函数
模板类与全特化:
//注意:无论是全特化还是偏特化,都必须有一个主模板
//调用优先级:全特化类>偏特化类>主版本模板类
// 主模板
// 模板函数
template<typename T, class C>
bool f(T t, C c){
return (t > c);
}
// 模板类
template<typename T, class C>
class F{
public:
bool f(T t, C c){
return (t > c);
}
};
// 全特化
template<>
bool f(int t, double c){
return (t > c);
}
template<>
class F{
public:
bool f(int t, double c){
return (t > c);
}
};
//偏特化
template<typename T>
bool f(T t, double c){
return (t > c);
}
template<class C>
class F{
public:
bool f(int t, C c){
return (t > c);
}
};
//调用函数
int a = 1;
double b = 2.0;
f<int, double>(a, b);
F<int, double>::f(a, b);
- 因非类型模板参数而造成的代码膨胀,可以用函数参数或类成员变量替换模板参数;因类型参数造成的代码膨胀,可以让带有完全相同二进制表述的具体类型共享实现码。
template<typename T, std::size_t s>
class D {
public:
void area(s){
...
}
};
// 当我们调用的时候,造成代码膨胀
D<double, 5> d1;
D<double, 10> d2;
d1.area();
d2.area();
//方法1. 共享同个基类,所以能共享同个show
template<typename T>
class B{
protected:
void area(std::size_t s);
};
template<typename T, std::size_t s>
class D : private B<T>{
private:
using B<T>::show;
public:
void area(){
this->area(s); //inline
}
};
// 方法2. 储存一个指针,指向数值所在内存
template<typename T>
class B{
protected:
B(std::size_t s, T* t) : size(s), data(t){}
void setData(T* t) { data = t;}
void area(){
...
}
private:
std::size_t size;
T* data;
};
template<typename T, std::size_t s>
class D : private B<T>{
public:
D() : B<T> (s, data)
private:
T data[s*s];
};
// 方法3. 将数据放进heap,通过new来分配内存
template<typename T>
class B{
protected:
B(std::size_t s, T* t) : size(s), data(t){}
void setData(T* t) { data = t;}
void area(){
...
}
private:
std::size_t size;
T* data;
};
template<typename T, std::size_t s>
class D : private B<T>{
public:
D() : B<T> (s, 0), data (new T[n*n]){ this->setData(data.get()); }
private:
boost::scoped_array<T> data;
};