对于变量,指定要从其初始化器自动推导出其类型。


对于函数,指定要从其 return 语句推导出其返回类型。
(C++14 起)

对于非类型模板形参,指定要从实参推导出其类型。
(C++17 起)

语法

auto (1) (C++11 起)
decltype(auto) (2) (C++14 起)
类型制约 auto (3) (C++20 起)
类型制约 decltype(auto) (4) (C++20 起)
类型制约 - 概念名,可以有限定,可以后随 <> 包围的模板实参列表

1,3) 用模板实参推导的规则推导类型。

2,4) 类型为 decltype(expr),其中 expr 是初始化器。

占位符 auto 可伴随如 const 或 & 这样的修饰符,它们参与类型推导。占位符 decltype(auto) 必须是被声明类型的唯一组分。 (C++14 起)

解释

占位符类型说明符可出现于下列语境:

  • 变量的类型说明符中:auto x = expr;。从初始化器推导类型。若占位符类型说明符为 auto 或 类型制约 auto (C++20 起),则采用从函数调用进行模板实参推导的规则,从初始化器推导变量的类型(细节见其他语境)。例如,给定 const auto& i = expr;,则 i 的类型恰是某个虚构模板 template void f(const U& u) 中参数 u 的类型(假如函数调用 f(expr) 通过编译)。因此,取决于初始化器,auto&& 可被推导成左值引用或右值引用类型,这被用于基于范围的 for 循环。

若占位符类型说明符为 decltype(auto) 或 类型制约 decltype(auto) (C++20 起),则推导出的类型为 decltype(expr),其中 expr 是初始化器。
(C++14 起)

若用占位符类型说明符声明多个变量,则推导出的类型必须互相匹配。例如,声明 auto i = 0, d = 0.0; 非良构,而声明 auto i = 0, *p = &i; 良构并将 auto 推导为 int。

  • new 表达式中的类型标识。从初始化器推导类型。对于 new T init(其中 T 含占位符类型,而 init 是带括号的初始化器或带花括号的初始化器列表),如同在虚设的声明 T x init; 中对变量 x 一般推导 T 的类型。
  • (C++14 起) 函数或 lambda 表达式的返回类型中:auto& f();。从其未弃用的 (C++17 起) return 语句的操作数推导返回类型。见返回类型推导
  • (C++17 起) 非类型模板形参的形参声明中:template struct A;。从对应的实参推导其类型。

此外,auto 与 类型制约 auto (C++20 起) 还可出现于:


- lambda 表达式的形参声明:{}。这种 lambda 表达式是泛型 lambda
- (C++20 起) 函数形参声明:void f(auto);。这种函数声明引入简写函数模板
(C++14 起)

若 类型制约 存在,令 T 为该占位符的被推导类型,则 T 必须满足 类型制约 的立即声明的制约。即,


- 若 类型制约 为 Concept<A1, …, An>,则制约表达式 Concept<T, A1, …, An> 必须合法并返回 true
- 否则(类型制约 为无实参列表的 Concept),制约表达式 Concept<T> 必须合法并返回 true
(C++20 起)

注解

C++11 之前,auto 具有存储期说明符的语义。

不允许在一个声明中混合 auto 的变量和函数,如 auto f() -> int, i = 0;。

auto 说明符亦可用于后随尾随返回类型的函数声明符,该情况下返回类型为其尾随返回类型(它也可以是占位符类型)。

  1. auto (*p)() -> int; // 声明指向返回 int 的函数的指针
  2. auto (*q)() -> auto = p; // 声明 q 为指向返回 T 的函数的指针
  3. // 其中 T 从 p 的类型推导

auto 说明符亦可用于结构化绑定声明。
(C++17 起)

auto 关键词亦可用于嵌套名说明符。形如 auto:: 的嵌套名说明符是一个占位符,其将遵循受制约类型占位符的推导规则被替换为某个类或枚举类型。
(概念 TS)

示例

运行此代码

  1. #include <iostream>
  2. #include <utility>
  3.  
  4. template<class T, class U>
  5. auto add(T t, U u) { return t + u; } // 返回类型是 operator+(T, U) 的类型
  6.  
  7. // 在其所调用的函数返回引用的情况下
  8. // 函数调用的完美转发必须用 decltype(auto)
  9. template<class F, class... Args>
  10. decltype(auto) PerfectForward(F fun, Args&&... args)
  11. {
  12. return fun(std::forward<Args>(args)...);
  13. }
  14.  
  15. template<auto n> // C++17 auto 形参声明
  16. auto f() -> std::pair<decltype(n), decltype(n)> // auto 不能从花括号初始化器列表推导
  17. {
  18. return {n, n};
  19. }
  20.  
  21. int main()
  22. {
  23. auto a = 1 + 2; // a 的类型是 int
  24. auto b = add(1, 1.2); // b 的类型是 double
  25. static_assert(std::is_same_v<decltype(a), int>);
  26. static_assert(std::is_same_v<decltype(b), double>);
  27.  
  28. auto c0 = a; // c0 的类型是 int,保有 a 的副本
  29. decltype(auto) c1 = a; // c1 的类型是 int,保有 a 的副本
  30. decltype(auto) c2 = (a); // c2 的类型是 int&,为 a 的别名
  31. std::cout << "a, before modification through c2 = " << a << '\n';
  32. ++c2;
  33. std::cout << "a, after modification through c2 = " << a << '\n';
  34.  
  35. auto [v, w] = f<0>(); // 结构化绑定声明
  36.  
  37. auto d = {1, 2}; // OK:d 的类型是 std::initializer_list<int>
  38. auto n = {5}; // OK:n 的类型是 std::initializer_list<int>
  39. // auto e{1, 2}; // C++17 起错误,之前为 std::initializer_list<int>
  40. auto m{5}; // OK:C++17 起 m 的类型为 int,之前为 initializer_list<int>
  41. // decltype(auto) z = { 1, 2 } // 错误:{1, 2} 不是表达式
  42.  
  43. // auto 常用于无名类型,例如 lambda 表达式的类型
  44. auto lambda = [](int x) { return x + 3; };
  45.  
  46. // auto int x; // 于 C++98 合法,C++11 起错误
  47. // auto x; // 于 C 合法,于 C++ 错误
  48. }

可能的输出:

  1. a, before modification through c2 = 3
  2. a, after modification through c2 = 4