一、class template定义
#include <vector>
#include <stdexcept>
template <typename T>
class Stack {
private:
std::vector elems;
public:
void push(const T&);
void pop();
T top() const;
bool empty() const {
return elems.empty();
}
};
template <typename T>
void Stack<T>::push(const T& elem)
{
elems.push_back(elem);
}
template <typename T>
void Stack<T>::pop()
{
if (elems.empty())
{
throw std::out_of_range("Stack::pop: empty stack");
}
elems.pop_back();
}
template <typename T>
T Stack<T>::top() const
{
if (elems.empty())
{
throw std::out_of_range("Stack::top: empty stack");
}
return elems.back();
}
二、使用class template
#include <iostream>
#include <string>
#include <cstdlib>
#include "stack1.hpp"
int main()
{
try {
Stack<int> intStack; // stack of ints
Stack<std::string> stringStack; // stack of strings
// manipulate int stack
intStack.push(7);
std::cout << intStack.top() << std::endl;
// manipulate string stack
stringStack.push("hello");
std::cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
}
catch (std::exception const& ex) {
std::cerr << "Exception: " << ex.what() << std::endl;
return EXIT_FAILURE; // exit program with ERROR status
}
}
代码只有在成员函数被调用时才被具现化。针对类模板而言,成员函数只有在被使用时才会被具现化。如果类模板中包含有静态成员,那些静态成员针对类型只会被实具现化一次。通过类模板具现化的类使用起来与其他类型一样。
对类模板类型参数的唯一要求就是针对类型参数的任何调用必须满足。
三、模板特化
完全特化:特化类型将作为template parameter并在class名称之后直接写明。如
#include <deque>
#include <string>
#include <stdexcept>
#include "stack.hpp"
template<>
class Stack<std::string>
{
private:
std::deque<std::string> elems;
public:
void push(const std::string&);
void pop();
std::string top() const;
bool empty() const {
return elems.empty();
}
};
void Stack<std::string>::push(const std::string& 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();
}
当模板类针对某个类型参数进行特化时,模板类中的所有成员函数也必须同时提供特化实现。
四、模板偏特化
class template可以被偏特化,这使得在特定情形下使用特殊实现代码,但仍然留出选择template parameter的能力。
template <typename T1, typename T2>
class MyClass {
...
};
//partial specialization: two template parameters are same
template <typename T>
class MyClass<T,T> { ... };
//partial specialization: 2nd template parameter is int
template <typename T>
class MyClass<T,int> { ... };
//partial specialization: two template parameters are pointers
template <typename T1, typename T2>
class MyClass<T1*, T2*> { ... };
五、默认模板参数
template <typename T, typename CONT=std::vector<T> >
class Stack {
private:
CONT elems;
public:
void push(const T&);
void pop();
T top() const;
bool empty() const { return elems.empty() }
};
...
使用带有默认模板参数时,如果与默认模板参数一致,不需要指定;否则需显式指定;如
Stack<double, std::deque<double> >
六:非类型模板类型参数(NON-TYPE TEMPLATE PARAMETER)
非类型参数主要是指值参数而非类型参数,通常是常整数、枚举、或者指向带有外链接对象的指针,浮点数或者class-type对象是不允许作为非类型模板参数的。在使用时,这个非类型模板参数必须显式指定。
小结摘要:
1. 所谓class template是包含一个或者多个尚未确定类型的class。
2. 必须将具体数据类型当做template parameter传入,才能使用class template。 于是该class template才能按照给定的template parameter数据类型,由编译器具现化并编译。
3. class template中,只有实际被调用的成员函数,才会被具现化。
4. 可以针对某些特别类型,对class template进行特化
5. 也可以针对某些特定类型,对class template进行偏特化
6. 可以为template parameter定义默认值