c++ template(二)

与函数相似,类也可以被一种或者多种类型参数化。

现在就让让我们看个简单的列子

#include
#include
template
class Stack {
public:
	void push(const T& elem);
	void pop();

private:
	std::vectorvec;
	std::size_t elemnumber;
};

template
void Stack::push(const T& elem) {
	if (elemnumber == vec.size())
		throw std::out_of_range("Stack is fill");
	vec.push_back(elem);
}

template
void Stack::pop() {
	if (elemnumber == 0)
		throw std::out_of_range("Stack is empty");
	vec.pop_back();  //只删除栈顶元素

}

int main(void)
{
	Stackstack;
	stack.pop();
}

从上文代码可以看出,定义类模板的成员函数,必须指定该成员函数是一个函数模板,而且还需要使用类模板的限定符。

template
void Stack::push(const T& elem) {
	if (elemnumber == vec.size())
		throw std::out_of_range("Stack is fill");
	vec.push_back(elem);
}

template
void Stack::pop() {
	if (elemnumber == 0)
		throw std::out_of_range("Stack is empty");
	vec.pop_back();  //只删除栈顶元素

}

那么我们怎么使用使用这个类模板,怎么使用成员函数呢?

int main(void)
{
	Stackstack; //模板的实例化,用模板实参int去替换模板参数T
	stack.pop();  //成员函数的调用
}

记住:实例化模板只实例化了成员函数的声明,具体调用哪个成员函数,才去实例化该成员函数的代码,这样可以节省时间与空间。

模板的实例化也可以理解为是模板的特化,通过模板的特化,可以优化基于某特定类型的实现,或者可以克服某种特定类型在实例化时所表现的不足(该类型没用提供某种操作,而模板特化有时候会隐时的支持)。模板的特化有两个重要的特化,首先让我来看看模板的全特化

template<> //注意尖括号里面没用模板参数
class Stack {   //非类型的模板
public:
	void push(int elem);
	void pop();

private:
	std::vectorvec;
	std::size_t elemnumber;
};


void Stack::push(int elem) {
	if (elemnumber == vec.size())
		throw std::out_of_range("Stack is fill");
	vec.push_back(elem);
}


void Stack::pop() {
	if (elemnumber == 0)
		throw std::out_of_range("Stack is empty");
	vec.pop_back();

}
int main(void)
{
	Stackstack;
	stack.pop();
}
  • 全特化也叫显示特化,它为模板提供了一种使模板参数可以全局替换的实现,而没用剩下模板参数。
  • 全特化的实现其实并不需要与主模板泛型实现有任何关联,它只和主模板的名称相关。言外之意就是说,全特化的模板里面的成员函数可以和主模板的成员函数不一样。    
  • 指定的模板实参列表必须和相应的模板参数列表对应。
  • 可以用全局模板的特化来代替泛型模板实例化的某个实体。

 

  全局特化的实质:全局特化的作用对象不是模板 ,它就类似与重新声明类或者函数。

 

全局特化通常是很有用的,但是有时我们更希望把类模板特化成一个“针对模板实参”的类家族,而不是针对“一个具体实参列表”的全局特化,因此我们引入了偏特化(局部特化)

template
class Stack {     
public:
	void push(const T& elem);
	void pop();

private:
	std::vectorvec;
	std::size_t elemnumber;
};

template
void Stack::push(const T& elem) {
	if (elemnumber == vec.size())
				throw std::out_of_range("Stack is fill");
			vec.push_back(elem);
}

template
void Stack::pop() {
	if (elemnumber == 0)
				throw std::out_of_range("Stack is empty");
			vec.pop_back();
}
int main(void)
{
	Stackstack;
	stack.pop();
}

其实我们还可以这样

template
class Stack {

};

template
class Stack {

};

template
class Stack {

};



template   //error
class Stack {   //必须出现 T2 ,不然无法推断出T2的类型

};

局部特化声明的实参必须和基本模板的相应参数在种类上是匹配的。

  • 局部特化的实参必须和基本模板的形参类型相匹配。

  

  • template
    class A;
    
    template
    class A;  //error 
    

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

  

  •  局部特化的参数列表不能有缺省实参,但局部特化仍然可以使用基本类模板的缺省实参。  

template
class A;

template //error
class A;

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 局部特化的非类型实参只能是非类型值,或者是普通的非类型模板参数;而不能是更复杂的依赖型表达式。

template
class A;

template
class A //error

局部特化的模板参数列表不能和基本模板的参数列表完全相同。

template
class A;

template
class A;

 

那么问题来了,在实际中我既实例化的主模板,有实例化了全特化的模板的,在调用成员函数时到底该调用哪一个呢?

c++  规定  全特化模板 > 偏特化模板 >主模板

 

你可能感兴趣的:(C++,template)