深入理解auto类型推导机制

一、auto是在c++11中被引入的,它的出现使得我们代码的更加的简洁。
例:
std::vector array;
std::vector::iterator it = array.begin();
// auto
auto it = array.begin();

二、auto的使用细则:
例1:
int x = 10;
auto ax = x;
问题1:这时候ax的类型是?auto被推导为?
回答以上问题,我们需要搞清楚一个概念。
问题2:什么是变量类型(即ax的类型)?什么是auto被推导的类型?
在这里,我们需要引入模板推导机制。
见:
https://blog.csdn.net/u011509616/article/details/75000204
https://blog.csdn.net/boydfd/article/details/49664213

这里引入模板函数:
//声明
template< typename T>
void f(ParamType param);
//调用
f(expr);

ParamType 为参数类型,可以理解为问题1中的变量类型。
T为模板参数类型,可以理解为问题1中的auto被推导类型。
f(expr);为模板的调用,expr为实参,它的类型为ParamType,根据它即可推导出T。
具体推导细节将在下面进行重点介绍。
回答了问题2后,再来回答问题1.
auto ax = x;
相当于编译器调用了模板函数
template< typename T>
void f(T param);
此为情形1,即ParamType为值拷贝类型。
调用函数为f(x). x的类型为int,故ParamType 为int,即ax的类型为int,推导出T的类型为int,故auto被推导的
类型为int。

例2:
int x = 10;
const auto bx = x;
这时候bx的类型是?auto被推导为?
首先:
编译器调用的函数模板为
template< typename T>
void f(const T param);
调用的函数为f(x).x的类型为int,此时的x类型上升为const int(解释见注释1),故ParamType 为const int,
bx的类型为const int。const auto为const int,故auto被推导为int。

例3:
const int x = 10;
const auto cx = x;
此实例推导过程同例2.

例4:
const int& x = 10;
const auto dx = x;
这时候dx的类型是?auto被推导为?
首先:
编译器调用的函数模板为
template< typename T>
void f(const T param);
调用的函数为f(x).x的类型为const int&,是否ParamType也为const int& 呢?
答案是否定的,ParamType为int,为什么?
理由: const int& 通过传值的方式生成副本,首先去掉const(原变量const不代表拷贝后的副本就是const,这很好理解)。其次去掉&(如果副本也是原变量的引用,那么当调用结束后,副本被释放,导致原变量的内存被释放,这是不合逻辑的**).
既然ParamType为int,这时候同例2了,即dx的类型为const int。const auto为const int,故auto被推导为int。

例5:
const int x = 10;
auto ex = x;
这时候ex的类型是?auto被推导为?
首先:
编译器调用的函数模板为
template< typename T>
void f(T param);
调用的函数为f(x).x的类型为const int,ParamType为int(解释见例4),ex的类型为int。auto为int,故auto被推导为int。

例6:
const int& x = 10;
auto fx = x;
此实例推导过程同例5.

以上几个实例可以帮我们很好理解以下规则:
1. 如果expr是一个引用类型,忽略引用部分。
2. 如果忽略了引用之后,expr含有const,同样忽略;volitale情形同const。

下面介绍情形2
例1:
int x = 10;
auto& ax = x;
这时候ax的类型是?auto被推导为?
首先:
相当于编译器调用了模板函数
template< typename T>
void f(T& param);
此为情形2,即ParamType为左值引用类型。
调用函数为f(x). x的类型为int&(此时需要上升到引用的角度,为什么?因为x本来就是个左值引用嘛**,为什么例1中x不能看作是int&,因为通过值拷贝的方式&会被去掉,这个在例4中说明),故ParamType 为int&,即ax的类型为int&,推导出T的类型为int,故auto被推导的类型为int。

例2:
int x = 10;
const auto& bx = x;
这时候bx的类型是?auto被推导为?
首先:
编译器调用的函数模板为
template< typename T>
void f(const T& param);
调用的函数为f(x).x的类型为int&(见上面例1的解释),此时的x类型上升为const int&(解释见注释1),故ParamType 为const int&,
bx的类型为const int&。const auto为const int&,故auto被推导为int&。

例3:
const int x = 10;
const auto& cx = x;
此实例推导过程同例2.

例4:
const int& x = 10;
const auto& dx = x;
此实例推导过程同例2.

例5:
const int x = 10;
auto& ex = x;
这时候ex的类型是?auto被推导为?
首先:
编译器调用的函数模板为
template< typename T>
void f(T& param);
调用的函数为f(x).x的类型为const int&,ParamType为const int&,ex的类型为const int&。auto&为const int&,故auto被推导为const int。

例6:
const int& x = 10;
auto& fx = x;
此实例推导过程同例5.

以上几个实例可以帮我们很好理解以下规则:
1.如果expr是一个引用类型,仍会保持const与volatile。
2.指针同引用。

最后介绍情形3
例1:
int x = 10;
auto&& ax = x;
这时候ax的类型是?auto被推导为?
首先:
相当于编译器调用了模板函数
template< typename T>
void f(T&& param);
此为情形3,即ParamType为右值引用类型。
调用函数为f(x). x的类型为int&(解释见情形2的例1),故ParamType 为int&,即ax的类型为int&,推导出T的类型为int&(见注释2),故auto被推导的类型为int&。

例2:
int x = 10;
const auto&& bx = x;
这时候bx的类型是?auto被推导为?
首先:
编译器调用的函数模板为
template< typename T>
void f(const T&& param);
调用函数为f(x). x的类型为int&(解释见情形2的例1),此时ParamType 为const int&(int& 隐式转化而来),即bx的类型为const int&,推导出T的类型为 int&(见注释2),故auto被推导的类型为int&。

例3:
const int x = 10;
const auto&& cx = x;
此实例推导过程同例2.

例4:
const int& x = 10;
const auto&& dx = x;
此实例推导过程同例2.

例5:
const int x = 10;
auto&& ex = x;
这时候ex的类型是?auto被推导为?
首先:
编译器调用的函数模板为
template< typename T>
void f(T&& param);
调用的函数为f(x).x的类型为const int&,ParamType为const int&,ex的类型为const int&。auto&&为const int&,故auto被推导为const int&(见注释2)。

例6:
const int& x = 10;
auto&& fx = x;
此实例推导过程同例5.

以上几个实例可以帮我们很好理解以下规则:
1. 如果expr为lvalue,T和ParamType全部推导为lvalue reference。这存在两个不同点:1. 这是在模版类型推导中唯一的一种情况:T推导为引用类型。2.虽然ParamType采用T&& 右值引用的声明语法,但是实际推导出的类型为lvalue reference。
2. 如果expr为lvalue,则采用情形2的推导方式。

这里写图片描述

可以按照我实例中介绍的思路,验证图中的结果**。

注释1:int可以隐式转化为const int,可以这么理解:const int比int范围小,可以理解const int为int的基类。而子类转化为父类是允许的。同理int&可隐式转化为const int&。
注释2:
auto&& 等价于int&,根据引用折叠原则(暂且忽略为什么),int& 等价于int&&&,于是auto&& 等价于 int&&&,消掉&&,auto推导为int&。

在阅读大牛们的一些文章后,自己的一些困惑油然而生,于是整理了思路,基于自己的理解写出了此文。
本文,仅仅作为一种记忆罢了,~个人崇尚在理解的基础上记忆~~
如果您也遇到类似的困惑,而在看了此篇文章后能给您一点点的明晰,我将甚是欣慰。

猜你喜欢

转载自blog.csdn.net/sxj_wyj/article/details/81904897
今日推荐