条款2: 理解auto型别推导
auto型别推导就是模板型别推导,除了一个例外。
对于模板型别推导的三种情况,auto型别推导的规则是一样的:
- 情况1 型别饰词是指针或引用 将原表达式的引用部分忽略
- 情况2 型别饰词是万能引用 若原表达式是左值 则推导为左值引用
- 情况3 型别饰词既非指针也非引用 将原表达式引用部分忽略 顶层const忽略
auto x = 27; // 情况3 x型别推导为int
const auto cx = x; // 情况3 cx型别推导为const int
const auto& rx = x; // 情况1 rx型别推导为const int&
auto&& uref1 = x; // 情况2 uref1型别推导为int&
auto&& uref2 = cx; // 情况2 uref2型别推导为const int&
auto&& uref3 = 27; // 情况2 uref3型别推导为int&&
对于数组和函数的推导规则,auto也是一样的。
const char name[] = "diwen"; // name的型别是const char[6]
auto arr1 = name; // arr1的型别是const char*
auto& arr2 = name; // arr2的型别是const (&)char[6]
void f(int, double); // f的型别是void(int, double)
auto func1 = f; // func1的型别是void(*)(int, double)
auto& func2 = f; // func2的型别是void(&)(int, double)
例外情况
对于 auto x{27}
这样的初始化语句,x推导出的型别是std::initializer_list
。而模板型别推导面对这样的情况就会失败:
template<typename T>
void f(T param);
f({1, 2, 3}); // 错误!无法推导T的型别
在C++14中,auto可以用来说明函数返回值需要推导,此时应用的不是auto型别推导,而是模板型别推导,因此下面代码无法通过编译:
auto f()
{
return {1, 2, 3};
}
在C++14中,auto可以用来指定lambda式的形参型别,此时也是应用模板型别推导,因此下面代码也无法通过编译:
auto f = [](const auto &v) {};
f({1, 2, 3});