在进入正题之前,我们先来看看什么时顶层const(high-level const)和底层const(low-level const)
简单点说,顶层const修饰的是数据类型本身,底层const不是.
举例:
const int i = 0;//顶层const,因为作用在int上
const int* p1 = &i;//底层const,因为作用在int上,而不是int*
int a = 0;
int* const p2 = &a;//顶层const,因为作用的是int*
const int& s = a;//底层const,因为作用的是int,而不是int&
现在进入正题
一般来说我们看到的函数模板都是下面的这个形式
template<typename T>
void f(ParamType param);
f(expr);
/*
其中paramType代表含T的表达式,比如:T,T*,T&
param就是变量名
expr就是实参
*/
现在第一种情况:ParamType既不是指针也不是引用
规则:
1.如果expr是引用,那么引用将会被忽略,如(int& 退化为 int)。
2.执行上一步后,如果expr中有顶层const,那么顶层const将会被忽略,如(const int 退化为 int)。
3.执行前两步之后,expr类型会和ParamType比较,取并集。得到就是ParamType的类型,T的类型就是在ParamType中去掉修饰的部分,如(ParamTypel:T*,那么去掉*,剩下的就是T的类型)。注意:ParamType的类型会被先推导出来,然后才是T的类型。
template<typename T>
void f(T param);
int x = 1;
const int cx = x;
int& rx = x;
const int& crx = x;
int* px = &x;
const int* const cpxc = &x;
f(x);//T为int,param的类型为int
f(cx);//T为int,param的类型为int
f(rx);//T为int,param的类型为int
f(crx);//T为int,因为&会先去掉变成了const int,此时const是顶层const,param的类型为int
f(px);//T为int*,param的类型为int*
f(cpxc);//T为const int*,param的类型为const int*
第二种情况 :ParamType是指针
规则:
1.如果expr是引用,那么引用将会被忽略,如(int& 退化为 int)。
2.执行上一步后,如果expr中有顶层const,那么顶层const将会被忽略,如(const int 退化为 int)。
3.执行前两步之后,expr类型会和ParamType比较,取并集。得到就是ParamType的类型,T的类型就是在ParamType中去掉修饰的部分,如(ParamTypel:T*,那么去掉*,剩下的就是T的类型)。注意:ParamType的类型会被先推导出来,然后才是T的类型。
template<typename T>
void f(T* param);
int x = 0;
const int cx = x;
int& rx = x;
const int& crx = x;
int* px = &x;
const int* const cpxc = &x;
f(&x); T为int,param的类型为int*
f(&cx);//T为const int,param的类型为const int*
/*
&cx相当于const int*类型,与T*并集为,const int*
所以ParamType为const int*,又因为ParamType是T*,
所以T为const int
*/
f(&rx);//T为int,param的类型为int*
f(&crx);//T为const int,param的类型为const int*
f(px);//T为int,param的类型为int*
f(cpxc);//T为const int,param的类型为const int*
第三种情况:ParamType是一个引用
规则:
1.如果expr是引用,那么引用将会被忽略,如(int& 退化为 int)。
2.执行前一步之后,expr类型会和ParamType比较,取并集。得到就是ParamType的类型,T的类型就是在ParamType中去掉修饰的部分,如(ParamTypel:T*,那么去掉*,剩下的就是T的类型)。注意:ParamType的类型会被先推导出来,然后才是T的类型。
这种情况最为简单,它不需要你用规则去推导就能一眼看出来,就像它引用的意义一样,ParamType的类型就是:去掉引用的expr的类型+&。那么T就是去掉引用的expr的类型。
template<typename T>
void f(T& param);
int x = 0;
const int cx = x;
int& rx = x;
const int& crx = x;
int* px = &x;
const int* const cpxc = &x;
f(x); T为int,param的类型为int&
f(cx);//T为const int,param的类型为const int&
f(rx);//T为int,param的类型为int&
f(crx);//T为const int,param的类型为const int&
f(px);//T为int*,param的类型为int*&
f(cpxc);//T为const int* const,param的类型为const int* const&
第四种情况:ParamType是个通用引用
规则:
1.expr是一个左值,执行第三种情况的规则,有点区别那就是T与ParamType的类型一样,都是引用。
2.expr是一个右值,执行第一种情况的规则。
template<typename T>
void f(T&& param);
int x = 0;
const int cx = x;
int& rx = x;
const int& crx = x;
int* px = &x;
const int* const cpxc = &x;
f(x);//T为int&,param的类型为int&
f(cx);//T为const int&,param的类型为const int&
f(rx);//T为int&,param的类型为int&
f(crx);//T为const int&,param的类型为const int&
f(px);//T为int*&,param的类型为int*&
f(cpxc);//T为const int* const&,param的类型为const int* const&
f(27);//T为int,param的类型为int&&