欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

effective c++条款总结(5)

程序员文章站 2022-07-12 17:52:10
...
  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;
};