现代C++之模板类型推导

描述

1.传统C++ VS 现代C++

传统C++中,参数的类型都必须明确定义,这其实对我们快速进行编码没有任何帮助,尤其是当我们面对一大堆复杂的模板类型时,必须明确的指出变量的类型才能进行后续的编码,这不仅拖慢我们的开发效率,也让代码变得又臭又长。

C++11 引入了类型推导,让编译器来操心变量的类型。这使得 C++ 也具有了和其他现代编程语言一样,某种意义上提供了无需操心变量类型的使用习惯。

下面代码中CoderWorld(1,"Traditional","C++")是传统C++写法而CoderWorld(2,"Modern","C++")是现代C++写法,虽然使用了模板,但是其用法就像调用没有使用模板的普通函数一样,这样的代码明显更加具有易读性。这是因为C++11引入了类型推导,编译器会自动推导出参数的类型。

template

2.模板类型参数推导

模板类型参数推导共分为四种情况,下面会分别对这四种情况进行详细阐述。

  1. 函数形参的类型为指针或引用类型,但不是通用引用类型
  2. 函数形参的类型为通用引用类型
  3. 函数形参的类型既不是指针也不是引用
  4. 数组或函数名
模板类型推导案例1
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 &类型。

模板类型推导案例2
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&&

模板类型推导案例3
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。

模板类型推导案例4

这是一种特殊的情况,就是当实参的类型是为数组和函数的时候需要注意。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)

3.模板类型推导总结

参数类型 例子 推导规则
指针或引用类型,但不是通用引用类型 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
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分