effective c++条款总结(5)

  1. 声明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());
	...
}
  1. 模板类名称使用,模板全特化与偏特化
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);
  1. 因非类型模板参数而造成的代码膨胀,可以用函数参数或类成员变量替换模板参数;因类型参数造成的代码膨胀,可以让带有完全相同二进制表述的具体类型共享实现码。
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;
};
上一篇:5.组件初使用


下一篇:C++ 低级错误之 Explicit specialization of undeclared template class 'xxx'