《C++ Templates》笔记——2.类模板

目录

1.类模板Stack的实现

2.类模板Stack的使用

3.类模板的特化

4.缺省模板实参


1.类模板Stack的实现

类模板的声明和函数模板的声明相似,下面是一个类模板Stack的例子,这个类的类型是Stack<T>,其中T是模板参数。然而,当时用类名而不是类的类型时,就应该只用Stack;比如,指定类的名称、类的构造函数、析构函数时。总结如下:

  • 和普通类的声明相似,先在类声明前加一行template <typename T>,然后将类声明中的数据类型换成虚拟类型参数T。
  • 类模板的成员函数在类模板外定义时必须指定成函数模板,且需要使用这个类模板的完整类型限定符Stack<T>::
#include <vector>
#include <stdexcept>

template <typename T>
class Stack{
private:
	std::vector<T> elems; //存储元素的容器
public:
	void push(T const&); //压入元素
	void pop(); //弹出元素
	T top() const; //返回栈顶元素
	bool empty() const { //返回栈是否为空
		return elems.empty();
	}
};

template <typename T>
void Stack<T>::push(T const& elem)
{
	elems.push_back(elem);
}

template <typename T>
void Stack<T>::pop()
{
	if (elems.empty())
	{
		throw std::out_of_range("Stack<T>::pop(): empty stack");
	}
	elems.pop_back(); //删除最后一个元素
}

template <typename T>
T Stack<T>::top() const
{
	if (elems.empty())
	{
		throw std::out_of_range("Stack<T>::pop(): empty stack");
	}
	return elems.back();  //返回最后一个元素的拷贝
}

2.类模板Stack的使用

类模板定义对象时形式为:类模板名<实际类型> 对象名类模板名<实际类型> 对象名(实参表列)。例如,Stack<int>  intStack。

Stack<int>          intStack;      //元素类型为int的栈
Stack<std::string>  stringStack;   //元素类型为字符串的栈

//使用int栈
intStack.push(7);
intStack.push('a');
std::cout << intStack.top() << std::endl;

//使用string栈
stringStack.push("chdayj");
std::cout << stringStack.top() << std::endl;
stringStack.pop();

同时,模板实参可以为任何类型: 

Stack<float*> floatStrStack;      //元素为浮点型指针的栈
Stack<Stack<int> > intStackStack; //元素为int栈的栈

注意,两个靠在一起的模板尖括号(即>) 之间要留一个空格;否则,编译器会误认为你在使用operator>>,从而导致语法错误。 

3.类模板的特化

因为类模板中的定义不一定适用于所有数据类型,所以针对此类型应该重新定义,即所谓类模板的特化。如果要特化一个类模板,自然要特化此类模板所有的成员函数。

3.1.全特化

特化的类上面应该加着templlate<>,并且特化后的类的类型应该将T换成具体的数据类型,比如int,string等。同时,每个成员函数都必须重新定义为普通函数。下面是一个用std::string特化Stack<>的完整例子。

#include <deque>
#include <stdexcept>
#include <string>

template<>
class Stack<std::string>{
private:
	std::deque<std::string> elems; //存储元素的容器
public:
	void push(std::string const&); //压入元素
	void pop(); //弹出元素
	std::string top() const; //返回栈顶元素
	bool empty() const { //返回栈是否为空
		return elems.empty();
	}
};

void Stack<std::string>::push(std::string const& elem)
{
	elems.push_back(elem);
}

void Stack<std::string>::pop()
{
	if (elems.empty())
	{
		throw std::out_of_range("Stack<<std::string>>::pop(): empty stack");
	}
	elems.pop_back(); //删除最后一个元素
}

std::string Stack<std::string>::top() const
{
	if (elems.empty())
	{
		throw std::out_of_range("Stack<<std::string>>::pop(): empty stack");
	}
	return elems.back();  //返回最后一个元素的拷贝
}

上面的例子中用deque而不是vector,说明:特化的实现可以和基本类模板的实现完全不同

3.2.局部特化

可以在特定的情况下指定类模板的特定实现,并且部分模板参数依然必须有用户来定义。例如类模板:

template <typename T1, typename T2>
class MyClass{
...
};

可以有以下几种局部特化:

//1.局部特化:两个模板参数具有相同的类型
template <typename T>
class MyClass<T, T>{
...
};

//2.局部特化:第2个模板参数类型为int
template <typename T>
class MyClass<T, int>{
...
};

//3.局部特化:两个模板参数都为指针类型
template <typename T1, typename T2>
class MyClass<T1*, T2*>{
...
};

下面的例子展示各种声明会使用哪个模板:

MyClass<int,float>   mif;     //使用MyClass<T1,T2>
MyClass<float,float> mFf;     //使用MyClass<T,T>
MyClass<float,int>   mfi;     //使用MyClass<T,int>
MyClass<int*,float*>   mp;    //使用MyClass<T1*,T2*>

如果有多个局部特化同等程度地匹配某个声明,那么该声明就具有二义性:

MyClass<int,int>    m;     //ERROR:同时匹配MyClass<T,T>和MyClass<T,int>
MyClass<int*,int*>  m;     //ERROR:同时匹配MyClass<T,T>和MyClass<T1*,T2*>

为了解决例子2中二义性,你可以另外提供一个指向相同类型指针的特化:

template <typename T>
class MyClass<T*, T*>{
...
};

4.缺省模板实参

我们上面例子中的类模板Stack<>是通过C++标准库的vector<>来实现的;因此,我们不需要亲自实现内存管理、拷贝构造函数和赋值运算符。同时,类模板还可以为模板参数定义缺省值,这些值称为缺省模板实参

#include <vector>
#include <stdexcept>

template <typename T, typename CONT = std::vector<T> >
class Stack
{
private:
	CONT elems; //存储元素的容器

public:
	void push(T const&); //压入元素
	void pop(); //弹出元素
	T top() const; //返回栈顶元素
	bool empty() const { //返回栈是否为空
		return elems.empty();
	}
};

template <typename T, typename CONT>
void Stack<T, CONT>::push(T const& elem)
{
	elems.push_back(elem);
}

template <typename T, typename CONT>
void Stack<T, CONT>::pop()
{
	if (elems.empty())
	{
		throw std::out_of_range("Stack<T, CONT>::pop(): empty stack");
	}
	elems.pop_back(); //删除最后一个元素
}

template <typename T, typename CONT>
T Stack<T, CONT>::top() const
{
	if (elems.empty())
	{
		throw std::out_of_range("Stack<T, CONT>::pop(): empty stack");
	}
	return elems.back();  //返回最后一个元素的拷贝
}

可以看到,上面的类模板有两个模板参数,因此每个成员函数的定义都必须具有这两个参数。我们仍然可以像前面的例子使用这个栈,就是说只传递第一个类型实参给这个类模板,将会利用vector来管理stack的元素。使用方式如下:

//int栈
Stack<int>          intStack;      

//double栈,使用std::deque来管理元素
Stack<double,std::deque<double> >  dblStack;   

参考:

《C++Templates》

C++ Template》第二版,2017年9月16日出版 Templates are among the most powerful features of C++, but they remain misunderstood and underutilized, even as the C++ language and development community have advanced. In C++ Templates, Second Editi on, three pioneering C++ experts show why, when, and how to use modern templates to build software that’s cleaner, faster, more efficient, and easier to maintain. Now extensively updated for the C++11, C++14, and C++17 standards, this new edition presents state-of-the-art techniques for a wider spectrum of applications. The authors provide authoritative explanations of all new language features that either improve templates or interact with them, including variadic templates, generic lambdas, class template argument deduction, compile-time if, forwarding references, and user-defined literals. They also deeply delve into fundamental language concepts (like value categories) and fully cover all standard type traits. The book starts with an insightful tutorial on basic concepts and relevant language features. The remainder of the book serves as a comprehensive reference, focusing first on language details and then on coding techniques, advanced applications, and sophisticated idioms. Throughout, examples clearly illustrate abstract concepts and demonstrate best practices for exploiting all that C++ templates can do. Understand exactly how templates behave, and avoid common pitfalls Use templates to write more efficient, flexible, and maintainable software Master today’s most effective idioms and techniques Reuse source code without compromising performance or safety Benefit from utilities for generic programming in the C++ Standard Library Preview the upcoming concepts feature The companion website, tmplbook.com, contains sample code and additional updates.
Templates are among the most powerful features of C++, but they remain misunderstood and underutilized, even as the C++ language and development community have advanced. In C++ Templates, Second Edition, three pioneering C++ experts show why, when, and how to use modern templates to build software that’s cleaner, faster, more efficient, and easier to maintain. Now extensively updated for the C++11, C++14, and C++17 standards, this new edition presents state-of-the-art techniques for a wider spectrum of applications. The authors provide authoritative explanations of all new language features that either improve templates or interact with them, including variadic templates, generic lambdas, class template argument deduction, compile-time if, forwarding references, and user-defined literals. They also deeply delve into fundamental language concepts (like value categories) and fully cover all standard type traits. The book starts with an insightful tutorial on basic concepts and relevant language features. The remainder of the book serves as a comprehensive reference, focusing first on language details and then on coding techniques, advanced applications, and sophisticated idioms. Throughout, examples clearly illustrate abstract concepts and demonstrate best practices for exploiting all that C++ templates can do. Understand exactly how templates behave, and avoid common pitfalls Use templates to write more efficient, flexible, and maintainable software Master today’s most effective idioms and techniques Reuse source code without compromising performance or safety Benefit from utilities for generic programming in the C++ Standard Library Preview the upcoming concepts feature The companion website, tmplbook.com, contains sample code and additional updates.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

遥感与地理信息

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值