一、类模板
…
6.特(例)化
将类模板针对特殊类型的特殊实现以独立的方式加以定义。
1)全模板特化
// 通用版本
template class Comparator { … };
// 特化版本
template<> class Comparator<char const*> { … };
Comparator ci; // 通用版本<-int
Comparator<char const*> cp; // 特化版本
代码:spec1.cpp
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
// 通用版本
template<typename T>
class Comparator {
public:
Comparator(T const& x, T const& y) :
m_x(x), m_y(y) {}
T const& max(void) const {
return m_x < m_y ? m_y : m_x;
}
T const& min(void) const {
return m_x < m_y ? m_x : m_y;
}
private:
T const& m_x;
T const& m_y;
};
// 全模板特化版本
template<>
class Comparator<char const*> {
public:
Comparator(char const* const& x,
char const* const& y) :
m_x(x), m_y(y) {}
char const* const& Max(void) const {
return strcmp(m_x, m_y) < 0 ?
m_y : m_x;
}
char const* const& Min(void) const {
return strcmp(m_x, m_y) < 0 ?
m_x : m_y;
}
private:
char const* const& m_x;
char const* const& m_y;
};
int main(void) {
int a = 123, b = 456;
Comparator<int> ci(a, b);
cout << ci.max() << ' '
<< ci.min() << endl;
double c = 1.23, d = 4.56;
Comparator<double> cd(c, d);
cout << cd.max() << ' '
<< cd.min() << endl;
string e = "world", f = "hello";
Comparator<string> cs(e, f);
cout << cs.max() << ' '
<< cs.min() << endl;
char g[] = "world", h[] = "hello";
Comparator<char const*> cp(g, h);
cout << cp.Max() << ' '
<< cp.Min() << endl;
return 0;
}
2)成员函数特化
只针对通用版本中部分成员函数给出满足特殊类型需要的特殊实现。
// 通用版本
template class Comparator {
…
T const& max(void) const { 一般实现 }
…
};
// 特化版本
template<>
char const* const& Comparator<
char const*>::max(void) const { 特殊实现 }
代码:spec2.cpp
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
// 通用版本
template<typename T>
class Comparator {
public:
Comparator(T const& x, T const& y) :
m_x(x), m_y(y) {}
T const& max(void) const {
return m_x < m_y ? m_y : m_x;
}
T const& min(void) const {
return m_x < m_y ? m_x : m_y;
}
private:
T const& m_x;
T const& m_y;
};
// 成员函数特化版本
template<>
char const* const& Comparator<
char const*>::max(void) const {
return strcmp(m_x, m_y) < 0 ? m_y : m_x;
}
template<>
char const* const& Comparator<
char const*>::min(void) const {
return strcmp(m_x, m_y) < 0 ? m_x : m_y;
}
int main(void) {
int a = 123, b = 456;
Comparator<int> ci(a, b);
cout << ci.max() << ' '
<< ci.min() << endl;
double c = 1.23, d = 4.56;
Comparator<double> cd(c, d);
cout << cd.max() << ' '
<< cd.min() << endl;
string e = "world", f = "hello";
Comparator<string> cs(e, f);
cout << cs.max() << ' '
<< cs.min() << endl;
char g[] = "world", h[] = "hello";
Comparator<char const*> cp(g, h);
cout << cp.max() << ' '
<< cp.min() << endl;
return 0;
}
7.局部特化
针对部分类型参数或类型参数中的部分约束条件所做的特化。
局部特化只能采用全模板特化的形式,不能针对成员函数做。
代码:spec3.cpp
#include <cstdlib>
#include <iostream>
using namespace std;
// 通用版本
template<typename T1, typename T2>
class Dual {
public:
static void print(void) {
cout << "Dual<T1,T2>" << endl;
}
};
// 针对第二个类型参数取short的局部特化版本
template<typename T>
class Dual<T, short> {
public:
static void print(void) {
cout << "Dual<T,short>" << endl;
}
};
// 针对两个类型参数取相同类型的局部特化版本
template<typename T>
class Dual<T, T> {
public:
static void print(void) {
cout << "Dual<T,T>" << endl;
}
};
// 针对两个类型参数取指针类型的局部特化版本
template<typename T1, typename T2>
class Dual<T1*, T2*> {
public:
static void print(void) {
cout << "Dual<T1*,T2*>" << endl;
}
};
// 针对两个类型参数取相同
// 类型指针的局部特化版本
template<typename T>
class Dual<T*, T*> {
public:
static void print(void) {
cout << "Dual<T*,T*>" << endl;
}
};
int main(void) {
Dual<int, char>::print();
Dual<int, short>::print();
Dual<int, int>::print();
Dual<int***, char*****>::print();
Dual<int*, int*>::print();
return 0;
}
8.缺省参数
类模板的模板参数可以带有缺省值,且必须靠后。
后面的参数可以用前面参数作为其缺省值。
代码:def.cpp
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename A=int, typename B=double,
typename C=string>
class X {
public:
static void print(void) {
cout << typeid(A).name() << ' '
<< typeid(B).name() << ' '
<< typeid(C).name() << endl;
}
};
/*
int mul(int x, int y = x) {
return x * y;
}
*/
template<typename A, typename B = A>
class Y {
public:
static void print(void) {
cout << typeid(A).name() << ' '
<< typeid(B).name() << endl;
}
};
int main(void) {
X<char, short, long>::print();
X<char, short>::print();
X<char>::print();
X<>::print();
//X::print();
//cout << mul(13) << endl;
Y<int>::print();
return 0;
}
9.非类型参数,即数值参数
template<…, 类型 非类型参数, …> class { … };
template<…, 类型 非类型参数, …> int foo(int x) { … }
代码:arg.cpp
#include <iostream>
using namespace std;
template</*typename*/class T, size_t S>
class Array {
public:
T& operator[](size_t i) {
return m_a[i];
}
T const& operator[](size_t i) const {
return const_cast<Array&>(*this)[i];
}
friend ostream& operator<<(ostream& os,
Array const& a) {
for (size_t i = 0; i < S; ++i)
os << '(' << a.m_a[i] << ')';
return os;
}
private:
T m_a[S];
};
int add(int x, int y) {
return x + y;
}
template<int x, int y>
int add(void) {
return x + y;
}
int main(void) {
Array<int, 5> ai;
for (int i = 0; i < 5; ++i)
ai[i] = (i + 1) * 10;
cout << ai << endl;
Array<string, 3> as;
//Array<string, 1+2> as;
//size_t two = 2;
//size_t const two = 2;
//size_t const volatile two = 2;
//Array<string, 1+two> as;
as[0] = "北京";
as[1] = "上海";
as[2] = "广州";
cout << as << endl;
cout << add(12, 15) << endl;
cout << add<12, 15>() << endl;
int x = 12, y = 15;
cout << add(x, y) << endl;
//cout << add<x, y>() << endl;
return 0;
}
可以作为模板非类型参数实参的只能是常量、常量表达式、带有常属性(const)的变量,但是不能同时带有挥发性(volatile)。
二、模板特性
1.typename
struct
/ 声明类
class \ 声明模板
/ 类型参数
typename \ 解决嵌套依赖,访问依赖于模板参数的嵌套类型
代码:typename.cpp
#include <iostream>
#include <typeinfo>
using namespace std;
class A {
public:
// 嵌套类型
typedef unsigned int UINT;
class B {};
};
template<typename T>
void foo(void) {
typename T::UINT u;
typename T::B b;
cout << typeid(u).name() << ' '
<< typeid(b).name() << endl;
}
int main(void) {
A::UINT u;
A::B b;
cout << typeid(u).name() << ' '
<< typeid(b).name() << endl;
foo<A>();
return 0;
}
2.template
/ 声明函数或类模板
template \ 解决嵌套模板,访问依赖于模板参数的嵌套模板
代码:template.cpp
#include <iostream>
#include <typeinfo>
using namespace std;
class A {
public:
// 嵌套模板
template<typename T>
void foo(void) const {
T t;
cout << typeid(t).name() << endl;
}
};
template<typename T1>
class C {
public:
// 嵌套模板
template<typename T2>
class D {
public:
void print(void) const {
cout << typeid(T1).name() << ' '
<< typeid(T2).name() << endl;
}
};
};
template<typename T>
void bar(T const& t) {
t.template foo<int>();
}
template<typename T>
void hum(void) {
typename C<T>::template D<string> d;
d.print();
}
int main(void) {
A a;
bar(a);
hum<double>();
return 0;
}
3.从类模板继承
代码:inherit.cpp
#include <cstdlib>
#include <iostream>
using namespace std;
template<typename T>
class A {
public:
class B {};
void foo(void) {}
int m_x;
void exit(int status) {
cout << "再见!" << endl;
}
};
template<typename T>
class C : public A<T> {
public:
void bar(void) {
typename A<T>::B b;
//A<T>::foo();
this->foo();
//A<T>::m_x = 10;
this->m_x = 10;
//A<T>::exit(0);
this->exit(0);
}
};
int main(void) {
C<int> c;
c.bar();
return 0;
}
在子类模板中访问那些依赖于模板参数的基类模板的成员,编译器在第一次编译时,通常会因为基类类型不明确而只在子类和全局作用域中搜索所引用的符号,导致编译失败,或调用全局函数。这时,应该在子类模板中通过作用域限定符,或者显式使用this指针,迫使编译器到基类作用域中搜索所引用的符号,产生正确的编译结果。
4.模板型模板参数
代码:tta.cpp
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T>
class A {
public:
T m_var;
};
template<typename T,
template<typename> class C>
class B {
public:
C<T> m_var; // A<int>
};
int main(void) {
B<int, A> b;
cout << typeid(b.m_var.m_var).name()
<< endl;
return 0;
}
在一个模板的参数表中,被typename声明的模板参数只能结合具体类型,不能结合模板,因此,如果需要通过模板参数接收从外部传入的类模板,需要将该模板参数声明为:
template<typename, …> class 参数名
的形式。
5.零初始化
代码:zero.cpp
#include <iostream>
using namespace std;
class Integer {
public:
Integer(int i = 0) : m_i(i) {}
friend ostream& operator<<(ostream& os,
Integer const& i) {
return os << i.m_i;
}
int m_i;
};
void foo(void) {
int i = int();
Integer n = Integer();
cout << i << endl;
cout << n << endl;
}
template<typename T>
void bar(void) {
T t = T();
cout << t << endl;
}
template<typename T>
class A {
public:
A(void) : m_t() {}
void foo(void) const {
cout << m_t << endl;
}
private:
T m_t;
};
int main(void) {
foo();
bar<int>();
bar<Integer>();
A<int> ai;
ai.foo();
A<Integer> an;
an.foo();
return 0;
}
对于基本类型的变量,如果在声明的同时没有指定初值,其值将是不确定的,而对于类类型的变量,即使声明时没有指定初值,其值也会经由缺省构造函数被设定为确定的初值。因此在函数模板和类模板中应该显式为局部变量和成员变量以零初始化语法的形式,设置初值。
局部变量:类型 变量 = 类型()
成员变量:初始化表 : 成员变量()
基本类型就会用相应类型的零值初始化:
整型:0
浮点型:0.0
字符串:""
布尔型:false
指针型:空指针
…
6.模板与虚函数
1)类模板和普通一样,也可以通过虚函数表现出多态性,但是因为实例化该类模板的类型实参可能并不能满足虚函数有效覆盖的条件,因此这种多态性并非针对所有类型实参都能表现出来。
代码:vf.cpp
#include <iostream>
using namespace std;
template<typename T>
class A {
public:
virtual void foo(T const& t) const {
cout << "A::foo" << endl;
}
};
template<typename T>
class B : public A<int> {
public:
virtual void foo(T const& t) const {
cout << "B::foo" << endl;
}
};
template<typename X, typename Y>
class C : public A<X> {
public:
virtual void foo(Y const& y) const {
cout << "C::foo" << endl;
}
};
int main(void) {
//A<int>* p = new B<int>;
A<int>* p = new B<double>;
p->foo(0);
//C<int, int> c;
C<int, double> c;
A<int>& r = c;
r.foo(0);
return 0;
}
2)基于虚函数 的多态机制,需要一个名为虚函数表的函数指针数组,该数组在类被编译或类模板被实例化的过程中产生,而此时那些模板形式的成员函数尚未被实例化,其入口地址和重载版本的个数,要等到编译器处理完对该函数的所有调用之后才能确定。成员函数模板的延迟编译阻碍了虚函数表的静态构建。因此虚函数不可能同时又是模板函数,或者模板形式的成员函数不可能同时又是虚函数。
哪些函数不能被声明为虚函数?
全局函数、静态成员函数、内联函数、构造函数、模板型成员函数
3)广义多态
动态多态:虚函数
静态多态:类模板
代码:dp.cpp
#include <iostream>
using namespace std;
class Shape {
public:
virtual void draw(void) const = 0;
};
class Circle : public Shape {
public:
void draw(void) const {
cout << "绘制圆形" << endl;
}
};
class Rect : public Shape {
public:
void draw(void) const {
cout << "绘制矩形" << endl;
}
};
// 绘制图形:多态函数
void draw(Shape const& shape) {
shape.draw();
}
int main(void) {
draw(Circle());
draw(Rect());
return 0;
}
代码:sp.cpp
#include <iostream>
using namespace std;
class Circle {
public:
void draw(void) const {
cout << "绘制圆形" << endl;
}
};
class Rect {
public:
void draw(void) const {
cout << "绘制矩形" << endl;
}
};
// 绘制图形:多态函数
template<typename Shape>
void draw(Shape const& shape) {
shape.draw();
}
int main(void) {
draw(Circle());
draw(Rect());
return 0;
}
7.编译模型
单一模型:声明、实现和使用同处于一个编译单元。
分离模型:声明、实现和使用分处于不同编译单元。
不适用于模板。
代码:div/
// 声明
template<typename T>
T const& min(T const& x, T const& y);
template<typename T>
T const& max(T const& x, T const& y);
template<typename T>
class Comparator {
public:
Comparator(T const& x, T const& y);
T const& min(void) const;
T const& max(void) const;
private:
T const& m_x;
T const& m_y;
};
// 实现
#include "cmp.h"
template<typename T>
T const& min(T const& x, T const& y) {
return x < y ? x : y;
}
template<typename T>
T const& max(T const& x, T const& y) {
return x < y ? y : x;
}
template<typename T>
Comparator<T>::Comparator(T const& x,
T const& y) : m_x(x), m_y(y) {}
template<typename T>
T const& Comparator<T>::min(void) const {
return m_x < m_y ? m_x : m_y;
}
template<typename T>
T const& Comparator<T>::max(void) const {
return m_x < m_y ? m_y : m_x;
}
// 使用
#include <iostream>
using namespace std;
#include "cmp.h"
int main(void) {
int a = 123, b = 456;
double c = 1.23, d = 4.56;
string e = "world", f = "hello";
cout << ::min(a, b) << ' '
<< ::max(a, b) << endl;
cout << ::min(c, d) << ' '
<< ::max(c, d) << endl;
cout << ::min(e, f) << ' '
<< ::max(e, f) << endl;
Comparator<int> ci(a, b);
cout << ci.min() << ' '
<< ci.max() << endl;
Comparator<double> cd(c, d);
cout << cd.min() << ' '
<< cd.max() << endl;
Comparator<string> cs(e, f);
cout << cs.min() << ' '
<< cs.max() << endl;
return 0;
}
包含模型:将位于不同编译单元中的声明、实现和使用汇集与同一个编译过程。
代码:inc/
// 声明
template<typename T>
T const& min(T const& x, T const& y);
template<typename T>
T const& max(T const& x, T const& y);
template<typename T>
class Comparator {
public:
Comparator(T const& x, T const& y);
T const& min(void) const;
T const& max(void) const;
private:
T const& m_x;
T const& m_y;
};
#include "cmp.cpp"
// 实现
template<typename T>
T const& min(T const& x, T const& y) {
return x < y ? x : y;
}
template<typename T>
T const& max(T const& x, T const& y) {
return x < y ? y : x;
}
template<typename T>
Comparator<T>::Comparator(T const& x,
T const& y) : m_x(x), m_y(y) {}
template<typename T>
T const& Comparator<T>::min(void) const {
return m_x < m_y ? m_x : m_y;
}
template<typename T>
T const& Comparator<T>::max(void) const {
return m_x < m_y ? m_y : m_x;
}
// 使用
#include <iostream>
using namespace std;
#include "cmp.h"
int main(void) {
int a = 123, b = 456;
double c = 1.23, d = 4.56;
string e = "world", f = "hello";
cout << ::min(a, b) << ' '
<< ::max(a, b) << endl;
cout << ::min(c, d) << ' '
<< ::max(c, d) << endl;
cout << ::min(e, f) << ' '
<< ::max(e, f) << endl;
Comparator<int> ci(a, b);
cout << ci.min() << ' '
<< ci.max() << endl;
Comparator<double> cd(c, d);
cout << cd.min() << ' '
<< cd.max() << endl;
Comparator<string> cs(e, f);
cout << cs.min() << ' '
<< cs.max() << endl;
return 0;
}
预实例化模型:将所有对模板的实例化编译过程提前到编译使用模板的代码之前。
代码:ins/
// 声明
template<typename T>
T const& min(T const& x, T const& y);
template<typename T>
T const& max(T const& x, T const& y);
template<typename T>
class Comparator {
public:
Comparator(T const& x, T const& y);
T const& min(void) const;
T const& max(void) const;
private:
T const& m_x;
T const& m_y;
};
// 实现
#include <string>
using namespace std;
#include "cmp.h"
template<typename T>
T const& min(T const& x, T const& y) {
return x < y ? x : y;
}
template<typename T>
T const& max(T const& x, T const& y) {
return x < y ? y : x;
}
template<typename T>
Comparator<T>::Comparator(T const& x,
T const& y) : m_x(x), m_y(y) {}
template<typename T>
T const& Comparator<T>::min(void) const {
return m_x < m_y ? m_x : m_y;
}
template<typename T>
T const& Comparator<T>::max(void) const {
return m_x < m_y ? m_y : m_x;
}
// 预实例化
template int const& min<int>(
int const&, int const&);
/*
template int const& max<int>(
int const&, int const&);
template double const& min<double>(
double const&, double const&);
template double const& max<double>(
double const&, double const&);
template string const& min<string>(
string const&, string const&);
template string const& max<string>(
string const&, string const&);
template class Comparator<int>;
template class Comparator<double>;
template class Comparator<string>;
*/
// 使用
#include <iostream>
using namespace std;
#include "cmp.h"
int main(void) {
int a = 123, b = 456;
double c = 1.23, d = 4.56;
string e = "world", f = "hello";
cout << ::min(a, b) << ' '
<< ::max(a, b) << endl;
cout << ::min(c, d) << ' '
<< ::max(c, d) << endl;
cout << ::min(e, f) << ' '
<< ::max(e, f) << endl;
Comparator<int> ci(a, b);
cout << ci.min() << ' '
<< ci.max() << endl;
Comparator<double> cd(c, d);
cout << cd.min() << ' '
<< cd.max() << endl;
Comparator<string> cs(e, f);
cout << cs.min() << ' '
<< cs.max() << endl;
return 0;
}