C++中auto关键字的用法

在最近几个 C++ 版本中,auto 越来越常见。很多人打趣说将来 C++ 里面一定全是 auto。本文介绍 C++ 中 auto(新)关键字的用法。

简介

auto 的作用:

  1. 对于变量,自动推导其类型
  2. 【C++14起】对于函数,自动推导返回值
  3. 【C++17起】对于非类型模板参数,自动推导其类型

有两种用法
【C++11起】auto
基于template type deduction进行推导。

在推导变量类型时,这种推导方式会将每个 auto 出现的地方代换做一个模板参数 U。U 的类型可以从等号左边的 P(下面的const auto&) 和等号右边的 A(下面的1+2)

1
2
3
4
const auto& x = 1 + 2; // P = const U&, A = 1 + 2

template<class U> void f(const U& u) {...}
const auto& x = f(1 + 2); // U = int, so the type of x is const int&

特别地,对于 copy-list-initialization 的情况,auto 要被代换为 initializer_list<U>。U 的类型同样可以从 P 和 A 推导出来。

1
2
3
auto l = {13}; // P = std::initializer_list<U>, A = {13}:
// deduced U = int, the type of l is std::initializer_list<int>
auto x1 = {3}; // x1 is std::initializer_list<int>

对于 direct-list-initialization 的情况,大括号内只允许有一个元素。

1
2
3
auto x2{1, 2}; // error: not a single element
auto x3{3}; // x3 is int
// (before N3922 x2 and x3 were both std::initializer_list<int>)

在推导返回值类型时,同样用模板参数 U 去替换。这个时候 A 就是 return 后面跟的表达式。如果有多个 return,那么它们推导出来必须是一样的。

1
2
auto f() { return 42; } // P = auto, A = 42:
// deduced U = int, the return type of f is int

【C++14起】decltype(auto)
类型是decltype(expr),expr 就是用来初始化的表达式。它不走上面的 template type deduction 逻辑。
那么这个到底有啥用呢?举几个例子

1
2
3
4
5
6
int i;
auto x3a = i; // decltype(x3a) is int
decltype(auto) x3d = i; // decltype(x3d) is int

auto x4a = (i); // decltype(x4a) is int
decltype(auto) x4d = (i); // decltype(x4d) is int&

如果一个函数返回右值引用,则其decltype(auto)是右值引用,但auto推导为值。

1
2
3
4
5
int&& f();
auto x5a = f();
static_assert(std::is_same<decltype(x5a), int>::value, "");
decltype(auto) x5b = f();
static_assert(std::is_same<decltype(x5b), int&&>::value, "");

对于大括号的形式

1
2
auto x6a = { 1, 2 };           // decltype(x6a) is std::initializer_list<int>
decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression

此外,decltype(auto)不能有其他的修饰了。

1
2
auto *x7a = &i;                // decltype(x7a) is int*
decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)

【C++23】auto 可以被用作显式类型转换。如auto (expr)auto {expr}

注意,在 trailing return type 中,auto 会在开头来开始这个声明。但它同样可以作为 placeholder 出现在尾部,虽然我也不知道意义在哪里。

1
2
3
auto (*p)() -> int; // declares p as pointer to function returning int
auto (*q)() -> auto = p; // declares q as pointer to function returning T
// where T is deduced from the type of p

Reference

  1. https://en.cppreference.com/w/cpp/language/auto