c++ template(二)

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

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

#include<iostream>
#include<vector>
template<typename T>
class Stack {
public:
	void push(const T& elem);
	void pop();

private:
	std::vector<T>vec;
	std::size_t elemnumber;
};

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

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

}

int main(void)
{
	Stack<int>stack;
	stack.pop();
}

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

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

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

}

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

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

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

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

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

private:
	std::vector<int>vec;
	std::size_t elemnumber;
};


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


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

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

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

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

template<typename T>
class Stack<T, std::size_t> {     
public:
	void push(const T& elem);
	void pop();

private:
	std::vector<T>vec;
	std::size_t elemnumber;
};

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

template<typename T>
void Stack<T, std::size_t>::pop() {
	if (elemnumber == 0)
				throw std::out_of_range("Stack is empty");
			vec.pop_back();
}
int main(void)
{
	Stack<int,std::size_t>stack;
	stack.pop();
}

其实我们还可以这样

template<typename T>
class Stack<T, T> {

};

template<typename T1>
class Stack<T1, int> {

};

template<typename T1,typename T2>
class Stack<T1*, T2*> {

};



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

};

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

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

  

  • template<typename T,int N=5>
    class A;
    
    template<typename T>
    class A<int, T>;  //error 
    

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

  

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

template<typename T,int N=5>
class A;

template<typename T=int> //error
class A<T, 5>;

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

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

template<typename T,int N=5>
class A;

template<int I>
class A<int,I*2> //error

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

template<typename T1,typename T2>
class A;

template<typename T,typename U>
class A;

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

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

发布了50 篇原创文章 · 获赞 11 · 访问量 4111

猜你喜欢

转载自blog.csdn.net/qq_43145594/article/details/89766231