当使用一个模板时,称为实例化模板。模板实例是编译器通过将模板参数应用于模板定义而创建的具体函数或类。模板实例又称为特化。因此,rational<int>
是模板rational<>
的一个特化。因此,特化是针对特定一组模板参数实现模板的过程。
C++允许为一个特定的模板参数集合定义一个定制的特化;也就是说,可以创建一个规则的例外情况。当你自己定义特化而不是让编译器为你实例化模板时,它被称为显式特化(也称为完全特化)。编译器自动创建的特化将是隐式特化。
使用template<>
开始一个显式特化的声明,告诉编译器正在编写一个显式特化,接下来是定义。注意类名是特化模板名称(例如Point<int>
),让编译器知道正在特化什么。在可以特化一个模板之前,必须告诉编译器类模板(即原始模板)的定义。通常,会在一个单独的头文件中先写类模板声明,后跟它的特化。
显式特化完全取代了模板参数的模板声明(如果模板接受多个参数,则必须为每个参数提供一个特定的值)。尽管惯例规定Point<int>
应该定义与主模板Point<>
相同的所有成员,但编译器并不强制执行此类限制。也就是说特化版本的具体实现可以与原始模板不同。
#include <iostream>
#include <vector>
template<class T>
class Point{
public:
Point(T x, T y):x_(x), y_(y){
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Point(const Point& pt): x_(pt.x_), y_(pt.y_){
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Point& operator=(const Point& pt)& {
Point(pt.x_, pt.y_).swap(static_cast<Point&>(*this));
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
Point(Point&& pt) noexcept: x_(pt.x_), y_(pt.y_) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Point& operator=(Point&& pt)& noexcept{
x_ = pt.x_;
y_ = pt.y_;
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
void swap(Point& pt) noexcept{
std::swap(x_, pt.x_);
std::swap(y_, pt.y_);
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
virtual ~Point(){
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
T getX()const{
return x_;
}
T getY()const{
return y_;
}
void moveTo(T x, T y);
/*【类内又有模板】方式一,在类内声明,在类外定义 */
template<class U>
U ratio() ;
/*【类内又有模板】方式二,在类内定义 */
template<class V>
V multiply() {
return static_cast<V>(x_) * static_cast<V>(y_);
}
private:
T x_;
T y_;
};
template<class T>
void Point<T>::moveTo(T x, T y){
x_ = x;
y_ = y;
}
template<class T>
template<class U>
U Point<T>::ratio() {
return static_cast<U>(x_) / static_cast<U>(y_); // omit devided by zero.
}
template<>
class Point<int>{
public:
Point(int x, int y):x_(x), y_(y){
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Point(const Point& pt): x_(pt.x_), y_(pt.y_){
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Point& operator=(const Point& pt)& {
Point(pt.x_, pt.y_).swap(static_cast<Point&>(*this));
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
Point(Point&& pt) noexcept: x_(pt.x_), y_(pt.y_) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Point& operator=(Point&& pt)& noexcept{
x_ = pt.x_;
y_ = pt.y_;
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
void swap(Point& pt) noexcept{
std::swap(x_, pt.x_);
std::swap(y_, pt.y_);
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
virtual ~Point(){
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int getX()const{
return x_;
}
int getY()const{
return y_;
}
void moveTo(int x, int y){
x_ = x;
y_ = y;
}
double ratio(){
std::cout << "Specialized version of type int.\n";
return static_cast<double>(x_) / static_cast<double>(y_); // omit devided by zero.
}
double multiply() {
return static_cast<double>(x_) * static_cast<double>(y_);
}
private:
int x_;
int y_;
};
int main() {
Point<int> pt1(1, 2);
Point<float> pt2(2.3f, 4.5f);
Point<double> pt3(2.3, 4.5);
pt1.ratio();
pt2.ratio<double>();
}
输出:
Point<int>::Point(int, int)
Point<T>::Point(T, T) [with T = float]
Point<T>::Point(T, T) [with T = double]
Specialized version of type int.
Point<T>::~Point() [with T = double]
Point<T>::~Point() [with T = float]
virtual Point<int>::~Point()
由输出可以看出int
版用的是特化版本,而且 double ratio()
的实现与原始模板也不同(输出了Specialized version of type int.
)。
Reference
Exploring C++ 11, 2nd Edition.