Understand auto
type deduction
除了一个例外,auto类型推导就是模版类型推导。
模板类型推导使用下面这个函数模板,
1 | template<typename T> |
而当一个变量使用auto
进行声明时,auto
扮演了模板中T
的角色,变量的类型说明符扮演了ParamType
的角色。例如:
1 | auto x = 27; |
我们可以认为生成了一些模板并推断出 auto 关键字的类型, 如下所示:
1 | template<typename T> //概念化的模板用来推导x的类型 |
Item1描述的三个情景稍作修改就能适用于auto:
- 情景一:类型说明符是一个指针或引用但不是通用引用
- 情景二:类型说明符一个通用引用
- 情景三:类型说明符既不是指针也不是引用
上文中描述了情况一和情况三,现在描述情况二:
1 | auto&& uref1 = x; //x是int左值, |
数组和函数名退化为指针同样适用于auto
类型推导,这里就不举例了。
但是, 这里有一个例外需要我们注意:当auto声明变量的初始值设定项括在花括号”{}“中时, 推导类型为 std::initializer_list. 如果不能推导出这样的类型, 代码将被拒绝编译。
1 | auto x1 = 27; //类型是int,值是27 |
这里发生了两种类型推导。一种是由于auto
的使用:使用花括号进行初始化的x5必须被推导为std::initializer_list
。但是std::initializer_list
是一个模板。std::initializer_list<T>
会被某种类型T
实例化,所以这意味着T
也会被推导。 在这个例子中推导之所以失败,是因为在花括号中的值并不是同一种类型。
因此auto
类型推导和模板类型推导的真正区别在于,auto
类型推导假定花括号表示std::initializer_list
而模板类型不能推导花括号。
C++14允许auto
用于函数返回值并会被推导,C++14的lambda函数也允许在形参声明中使用auto
。但是在这些情况下auto
使用模板类型推导的规则,而不是auto
类型推导。因此, 具有返回花括号初始化器的auto返回类型的函数将无法编译:
1 | auto createInitList() |
重点
- auto类型推导通常与模板类型推导相同, 但auto类型推导假定花括号(“{}“)初始化表示 std::initializer_list,而模板类型推导则不然。
- 函数返回类型或 lambda 参数中的 auto 表示模板类型推导,而不是auto类型推导。