EMCPP条款2:理解auto型别推导

YiQi 管理员

除了一个奇妙的例外情况以外,auto 型别推导就是模板型别推导。

与条款1类似,也存在三种情况:

  • 情况1:型别饰词是指针或引用,但不是万能引用。
  • 情况2:型别饰词是万能引用。
  • 情况3:型别饰词既非指针也非引用。
1
2
3
auto x = 27;        // 情况3,x为int
const auto cx = x; // 情况3,cx为const int
const auto& rx = x; // 情况1,rx为const auto&

对于情况2:

1
2
3
auto&& uref1 = x;   // x是左值,uref1的型别是int&
auto&& uref2 = cx; // cx是左值,uref2的型别是const int&
auto&& uref3 = 27; // 27是右值,uref3的型别是int&&

条款1以一段数组和函数名字如何在非引用型别饰词的前提下退化成指针的讨论收官。同样的结论也适用 auto 型别推导:

1
2
3
4
5
6
const char name[] = "R. N. Briggs"; // name的型别是const char[13]
auto arrl = name; // arr1的型别是const char*
auto& arr2 = name; // arr2的型别是const char (&)[13]
void someFunc(int, double);
auto func1 = someFunc; // func1的型别是void (*)(int, double)
auto& func2 = someFunc; // func2的型别是void (&)(int, double)

C++11之后有四种方法声明一个int并初始化:

1
2
3
4
int x1 = 27;
int x2(27);
int x3 = { 27 };
int x4{ 27 };

也可以使用 auto声明并初始化:

1
2
3
4
auto x1 = 27;
auto x2(27);
auto x3 = { 27 };
auto x4{ 27 };

注意,前两个与使用 int 时一样,而后面两个的型别是 std::initializer_list<int>,且含有单个值为27的元素

经过测试发现 x3std::initializer_list<int>x4int

这样一来,如果型别推导失败,就通不过编译,比如:

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
2
3
4
auto x = { 11, 23, 9 }; // x's type is std::initializer_list<int>
template<typename T> // template with parameter
void f(T param); // declaration equivalent to x's declaration
f({ 11, 23, 9 }); // error! can't deduce type for T

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
2
3
4
5
template<typename T>
void f(std::initializer_list<T> initList);
f({ 11, 23, 9 });
// T deduced as int, and initList's
// type is std::initializer_list<int>

一般只在必要的时候才会使用大括号括起的初始化表达式(至于什么是必要的时候,请参见条款 7)。

关于C++11, 上面所说的就是全部了。但是关于C++14, 还有别的话要说。见条款3

要点速记

  • 在一般情况下,auto 型别推导和模板型别推导是一模一样的,但是 auto 型别推导会假定用大括号括起的初始化表达式代表一个 std::initializer_list,但模板型别推导却不会。
  • 在函数返回值或 lambda 式的形参中使用 auto,意思是使用模板型别推导而非 auto 型别推导。
此页目录
EMCPP条款2:理解auto型别推导