传统C++中,参数的类型都必须明确定义,这其实对我们快速进行编码没有任何帮助,尤其是当我们面对一大堆复杂的模板类型时,必须明确的指出变量的类型才能进行后续的编码,这不仅拖慢我们的开发效率,也让代码变得又臭又长。
C++11 引入了类型推导,让编译器来操心变量的类型。这使得 C++ 也具有了和其他现代编程语言一样,某种意义上提供了无需操心变量类型的使用习惯。
下面代码中CoderWorld(1,"Traditional","C++")是传统C++写法而CoderWorld(2,"Modern","C++")是现代C++写法,虽然使用了模板,但是其用法就像调用没有使用模板的普通函数一样,这样的代码明显更加具有易读性。这是因为C++11引入了类型推导,编译器会自动推导出参数的类型。
template
模板类型参数推导共分为四种情况,下面会分别对这四种情况进行详细阐述。
template<typename T>
void CoderWorld(T& param);
int x = 27;
const int& rx = x;
CoderWorld(rx); // T is const int, param's type is const int&
上述代码中函数CoderWorld(T& param)中形参的类型是引用类型(即T&), 推导遵循的规则如下:
在函数形参的类型为指针或引用类型,但不是通用引用类型情况下,需要去掉实参类型中的引用(这里的去掉引用是指去掉实参类型的引用,而不是形参param的类型T&中的&)。
对于CoderWorld(rx),实参rx为const int&类型,根据上述应该去掉实参rx 类型的引用,即将const int&中的&去掉,因此T被推导为const int 类型,最终param的类型T&为const int &类型。
template<typename T> void CoderWorld(T&& param);
int x = 27;
const int cx = x;
const int& rx = x;
CoderWorld(cx);//cx is lvale,so T is const int&, param's type is const int&
CoderWorld(27);//27 is rvale,so T is int,param's type is int&&
上述代码中函数CoderWorld(T&& param) 形参类型是通用引用类型(即T&&),推导规则遵循如下:
在函数形参的类型为通用引用类型情况下,当实参的类型是左值时,param的类型和T的类型均为左值引用,当实参的类型是右值时,T的类型与实参一致,param的类型是实参类型的右值引用。
代码中cx是一个左值,因此T的类型与形参param的类型均推导为左值引用const int &。
当CoderWorld传入的参数是27时,因为27是右值,所以T的类型推导为int,param的类型推导为右值引用int&&
template<typename T> void CoderWorld(T param);
const int cx = x;
const int& rx = x;
CoderWorld(cx);//T and param are both int
CoderWorld(rx);// T and param are both int
上述代码中CoderWorld(T param)形参类型T即不是指针也不是引用类型,实际上是值传递,也就是说这种情况下形参param是实参的一个拷贝,推导规则遵循如下:
在函数形参的类型既不是指针也不是引用类型的情况下,如果实参的类型有引用,则忽略掉引用部分,如果实参类型有const,则忽略掉const部分,如果有volatile也忽略掉。
代码中实参cx的类型为const int,因此忽略掉const之后T的类型为int,形参param的类型也为int。
代码中实参rx的类型为const int &,去掉引用和const之后T的类型为int,形参param的类型也为int。
这是一种特殊的情况,就是当实参的类型是为数组和函数的时候需要注意。C++中,数组可以退化成指针,一个函数类型也是可以退化成指针的。具体的情况如下代码所示,结合注释记住这段代码中的CoderWorld1和CoderWorld2对数组和函数的推导情况即可。
template<typename T>
void CoderWorld1(T param);
template <typename T>
void CoderWorld2(T& param);
int arr = {0,1,2,3};
void someFunc(int,double);
CoderWorld1(arr);//arr会退化成指针,即param的类型为int*
CoderWorld2(arr);//这里很有意思,param会被推导为 int (&)[4]
//和上面的情况相比好处是param包含了数组的元素数量信息,可以获取到数组的成员数。
CoderWorld1(someFunc);//param类型为函数指针 void (*)(int,double)
CoderWorld2(someFunc);//param类型为函数引用 void (&)(int,double)
参数类型 | 例子 | 推导规则 |
---|---|---|
指针或引用类型,但不是通用引用类型 | template void CoderWorld(T& param);void CoderWorld(T* param); | 忽略实参引用 |
通用引用类型 | templatevoid CoderWorld(T&& param); | 实参为左值param为左值引用实参为右值param为右值引用 |
既不是指针也不是引用 | templatevoid CoderWorld(T param); | 忽略引用和const类型 |
数组或函数名 | CoderWorld(arr)CoderWorld(someFunc) | 数组退化为指针函数退化为函数指针image |
全部0条评论
快来发表一下你的评论吧 !