本章节主要针对于template的类型推到进行一个简介;
对于一下template模板:
template<typename T>
void fun(ParamType param);
fun(expr);
以往自己认为T的类型是由expr来决定的,之后作用于ParamType,但是今天看了这张发现自己的理解有点问题;
事实情况是T的类型是什么取决于ParamType以及expr的具体形式,并不是孤立存在的;
因此,T的类型不仅取决于expr的类型,也取决于ParamType的类型;
本章节对ParamType分了三种场景,并且结合expr的类型,对T的推断进行讨论;
分别为三种情况:
- ParamType为指针或者引用(不是右值万能引用);
- ParamType为万能引用;
- ParamType既不是指针,也不是引用;
1. ParamType是指针或引用:
template<typename T>
void fun(T& param);
fun(expr);
对于该种情况,主要有两条严格规律:
(1)expr的引用类型会被忽略;
个人认为原因是由于param已经为引用,因此如果T不能再推断为引用,否则将变为万能引用形式;
(2)之后对expr的型别和ParamType的型别执行匹配,来确定T的型别;
主要目的是确定其他修饰符,例如const等是否参与类型推导;
例如:
const int& rx=x;
f(rx);//T的类型被推导为const int,param的类型是const int&;
对于上述的rx,首先剥除引用,之后由于为const int,所以T应该为const int,从意愿上我们也希望const对象传入后,也应该当作为const类型在模板中进行处理;
再比如:
template<typename T>
void f(const T& param);
const int& rx=x;
f(rx);//T的类型被推导为int,param的类型是const int&;
从上述可看,由于形参已经带有const,所以T就没必要带const;
针对于指针类型也是同理:
template<typename T>
void f(T* param);
const int* rx=x;
f(rx);//T的类型被推导为const int,param的类型是const int*;
推断方法和上述类似,因此T的具体类型取决于expr和Param两者共同作用;
2. ParamType是万能引用:
这点和右值引用有关;
template<typename T>
void fun(T&& param);
fun(expr);
对于如果传输的是右值,需要右值引用来接收该值,但是实际模板推导不一定传输的为右值,也有可能为左值;
对于该种情况,则针对于模板实例化进行判断:
如果是左值,则改为左值的引用,因为右值不允许直接接收左值;
如果为右值,则直接接收,获取类型;
例如:
const int& x=27;
fun(x);//左值,降级去引用,用于是const引用,所以T为const int&;
fun(25);//右值,应该为右值引用,所以为fun的形参应该为int&&,T为int;
3. ParamType常规拷贝类型:
形式如下:
template<typename>
void fun(T param)
此时可以认为形参为实参的拷贝,因此常规的const对象可能被忽略;
因此有两条经典规则:
(1)应该忽略expr的引用情况;
(2)如果为const对象,即不可修改,由于值拷贝的特性,也应该给予忽略;
但是针对于const类型,有一种情况需要注意一下;
对于指针也可以采用拷贝类型进行参数判断,考虑指针
const char* const ptr="123"
f(ptr);//此时应该判断为char* const类型;
const char* const 为一个常量指针指向一个常量;
但是值拷贝只能消除常量指针特性,但是还是只能指向常量,因此类型判断应该是char* const;
关于数组实参:
传统数组存在降级的问题,也就是一个数组指针会被判断为一个单指针;
但是这里提出了一种新的可以推导数组的方法,并且可以用于辅助其他数组实例化;
template<typename T>
void f(T& param);
f(name);//此时被推导为const char& [n],其中n为name数组的大小;
因此,可以用于实例化之中;
template<typename T,std::size_t N>
constexpr std::size_t arrSize(T (&)[N]) noexcept{
return N;
}
int keys[]={1,2,3,4,5,6};
int new_array[arrSize(keys)];
可以在便编译期间利用该函数获得数组大小,用于后续的赋值;