显示具体化:explict specialization
对于给定的函数名,可以有:
- 非模板函数
- 模板函数
- 显式具体化模板函数
- 上述的重载版本
显示具体化格式:以template<>开始,在函数名称后面通过\<x>指出具体类型
具体化优先于常规模板,非模板函数优先于具体化
template <typename T>
void swap(T &, T &);
template<> void swap(job &, job &);
//或者
template<> void swap<job>(job &, job &);
实例化(instantiation)
显式实例化:直接命令编译器创建特定类型的实例
声明特定的种类并且在声明前加上关键字template
例子:
template void swap<int>(int,int);//使用swap模板生成int类型的函数定义
注意显示实例化与显示具体化的不同:具体化是指:不要用函数模板生成swap函数的定义,而应该专门为int类型显式定义函数定义
使用函数创建显式实例化:
template <class T>
T add(T a, T b)
{
return a+b;
}
int m = 6;
double x = 10.2;
cout << add(x,m) << endl; //报错,类型不匹配
cout << add<double>(x, m) << endl; //explict instantiation
//本来m是int x是double 不匹配,但是显示实例化为double后就可以转型了
隐式实例化,显式实例化,显式具体化统称为具体化(specilization)
对于函数重载,函数模板和函数模板重载,编译器的选择优先级:
may('B');
void may(int);//1
float may(float, float = 3);//2
void may(char);//3
char* may (const char *);//4
char may(const char &);//5
template<class T> void may(const T &);//6
template<class T> void may(T *);//7
注意只考虑特征标不考虑返回类型
4和7不可行,因为整数类型不能被隐式转换为指针,其他可行
决定顺序:
- 完全匹配,但常规函数优先于模板
- 提升转换,char到int等 float到double
- 标准转换 int到char long到double
- 用户定义的转换,如类中定义的
1优于2,因为char到int是提升转换,char到float是标准转换
3,5,6优于1,2因为完全匹配
3,5优于6,因为6是模板
完全匹配允许的无关紧要转换:
从实参 | 到形参 |
---|---|
T | T & |
T & | T |
T [] | * T |
T | const T |
T | volatile T |
T * | const T |
T * | volatile T * |
blot ink;
recycle(ink);
//以下都是完全匹配
void recycle(blot); //blot to blot
void recycle(const blot); //blot to const blot
void recycle(blot &); //blot to blot &
void recycle(const blot &); //blot to const blot &
以下情况下,即使两个函数完全匹配也能重载解析
比如只有3,4 则会选择3,因为ink不是const
但是如果只有1,2则会报错,因为const的区别只适用于指针和引用
还有一种一个完全匹配优于另一个的情况:非模板和模板函数
如果两个完全匹配函数都是模板函数则"具体"的优先,即显式具体化将优先于隐式具体化
template <class T> void recycle (T t);
template <> void recycle<blot> (blot & t);//优先
"具体"意味着编译器执行转换最少如:
template <class T> void recycle (T t);
template <class T> void recycle (T * t);
recycle(&ink);
对于1,T解释为blot * 对2,T解释为ink ,2更具体
总结:
重载解析寻找最匹配的函数,如果只存在一个这样的函数,选择它;如果存在多个,但只有一个是非模板函数,选择它;如果存在多个都是模板函数,但有一个更加具体,选择它。如果有多个合适的但没有一个更加具体则报错,没有合适的也报错
lesser(x,y);
lesser<>(m,n);//要求编译器使用模板函数
lesser<int>(m,n);//要求显式实例化 (函数调用的方式)
decltype c++11
int x;
decltype(x) y; //y和x的类型一样
decltype(x+y) xpy= x + y;
decltype(expression) var;
//第一步,如果expression是一个没有用括号的标识符,则var类型与其相同
double x = 5.5;
double y = 7.9;
double & rx = x;
const double * pd;
decltype(x) w; //w is type double
decltype(rx) u = y; //u is type double &;
decltype(pd) v; //v is type const double *
//第二步,如果expression是一个函数调用,则var类型与该函数的返回类型相同
long indeed(int);
decltype(indeed(3)) m; //m is type int;
//不会实际调用函数,编译器只是查看一下该函数的返回类型而已
//第三步,如果expression是一个左值,则var为指向其类型的引用 括号括起
double xx = 4.4;
decltype ((xx)) r2 = xx; //r2 is double &
decltype (xx) w = xx; //w is double
//第四步,如果前面条件都不满足,则var类型与expression类型相同
int j = 3;
int & k = j;
int & n = j;
decltype(j+6) i1; // i1 type int
decltype(100L) i2; //i2 type long
decltype(k+n) i3; //i3 type int
//k,n是引用但是k+n不是
typedef decltype(x+y) xytype;
xytype xpy = x + y;
给decltype提供的参数可以是表达式
template<class T1, class T2>
?type? gt(T1 x, T2 y) {
...
return x + y;
}
double h(int x, float y);
//c++11新增语法
auto h(int x, float y) -> double;
//结合
template<class T1, class T2>
auto gt(T1 x, T2 y) -> decltype(x + y)
{
...
return x + y;
}
()