EMCPP条款2:理解auto型别推导
除了一个奇妙的例外情况以外,auto
型别推导就是模板型别推导。
与条款1类似,也存在三种情况:
- 情况1:型别饰词是指针或引用,但不是万能引用。
- 情况2:型别饰词是万能引用。
- 情况3:型别饰词既非指针也非引用。
1 | auto x = 27; // 情况3,x为int |
对于情况2:
1 | auto&& uref1 = x; // x是左值,uref1的型别是int& |
条款1以一段数组和函数名字如何在非引用型别饰词的前提下退化成指针的讨论收官。同样的结论也适用 auto
型别推导:
1 | const char name[] = "R. N. Briggs"; // name的型别是const char[13] |
C++11之后有四种方法声明一个int并初始化:
1 | int x1 = 27; |
也可以使用 auto
声明并初始化:
1 | auto x1 = 27; |
注意,前两个与使用 int
时一样,而后面两个的型别是 std::initializer_list<int>
,且含有单个值为27的元素
经过测试发现
x3
是std::initializer_list<int>
而x4
是int
这样一来,如果型别推导失败,就通不过编译,比如:
1 | auto x5 = {1, 2, 3.0}; |
注意使用 auto
和大括号时,发生了两种推导,第一种是 auto
的推导,推导出 std::initializer_list<T>
模板,第二种是推导出 T
。
遍历形如
auto x = {1, 2, 3}
这种初始化列表的话,需要使用for (auto v : x)
,不能indexing。
When an auto
–declared variable is initialized with a braced initializer, the deduced type is an instantiation of std::initializer_list
. But if the corresponding template is passed the same initializer, type deduction fails, and the code is rejected:
1 | auto x = { 11, 23, 9 }; // x's type is std::initializer_list<int> |
However, if you specify in the template that param
is a std::initializer_list<T>
for some unknown T
, template type deduction will deduce what T
is:
1 | template<typename T> |
一般只在必要的时候才会使用大括号括起的初始化表达式(至于什么是必要的时候,请参见条款 7)。
关于C++11, 上面所说的就是全部了。但是关于C++14, 还有别的话要说。见条款3
要点速记
- 在一般情况下,
auto
型别推导和模板型别推导是一模一样的,但是auto
型别推导会假定用大括号括起的初始化表达式代表一个std::initializer_list
,但模板型别推导却不会。 - 在函数返回值或
lambda
式的形参中使用auto
,意思是使用模板型别推导而非auto
型别推导。