auto 指定符(C++11 起)

来自cppreference.com
< cpp‎ | language

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

对于函数,指定其返回类型是尾随的返回类型或将从其 return 语句推导出 (C++14 起)

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

目录

[编辑] 语法

auto variable initializer (1) (C++11 起)
auto function -> return type (2) (C++11 起)
auto function (3) (C++14 起)
decltype(auto) variable initializer (4) (C++14 起)
decltype(auto) function (5) (C++14 起)
auto :: (6) (概念 TS)
cv(可选) auto ref(可选) parameter (7) (C++14 起)
template < auto Parameter > (8) (C++17 起)
cv(可选) auto ref(可选) [ identifier-list ] initializer ; (9) (C++17 起)

[编辑] 解释

1) 在块作用域、命名空间作用域、循环初始化语句等中声明变量时,关键词 auto 可用作类型指定符。

只要初始化器的类型被确定,则编译器会用来自函数调用的模板实参推导规则所决定的类型替换关键词 auto (细节见模板实参推导)。关键词 auto 可与修饰符组合,如 const& ,它们将参与类型推导。例如,给出 const auto& i = expr;i 的类型恰是虚构模板 template<class U> void f(const U& u) 中参数 u 的类型,倘若函数调用 f(expr) 被编译。从而, auto&& 可根据初始化器被推导成左值或是右值引用,这被用于基于范围的for循环。

auto 被用于声明多个变量,则推导类型必须相符。例如,声明 auto i = 0, d = 0.0; 为病式,而声明 auto i = 0, *p = &i; 为良式,这里 auto 被推导成int
2) 在使用尾随返回类型语法的函数声明中,关键词 auto 不进行自动类型检测。它只作为语法的一部分起作用。
3) 在不使用尾随返回类型语法的函数声明中,关键词 auto 指示返回类型将通过其 return 语句的运算数,用模板实参推导规则推导出。
4) 若变量的声明类型是 decltype(auto) ,则关键词 auto 被替换成其初始化器的表达式(或表达式列表),而实际类型以 decltype 规则推导。
5) 若声明函数返回类型为 decltype(auto) ,则关键词 auto 被替换成其返回语句的运算数,而其实际返回类型以 decltype 规则推导。
6) 拥有形式 auto:: 的嵌套名称指定符是占位符,它会被类或枚举类型遵循制约类型占位符推导规则替换。
7) lambda 表达式中的参数声明。 (C++14 起)函数参数声明。 (概念 TS)
8)模板形参声明为 auto ,则其类型由对应使用参数推导出。

[编辑] 注意

C++11 前, auto 拥有存储期指定符的语义。

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

[编辑] 示例

#include <iostream>
#include <utility>
 
template<class T, class U>
auto add(T t, U u) { return t + u; } // 返回类型是 operator+(T, U) 的类型
 
// 在其所调用的函数返回引用的情况下
// 函数调用的完美转发必须用 decltype(auto)
template<class F, class... Args>
decltype(auto) PerfectForward(F fun, Args&&... args) 
{ 
    return fun(std::forward<Args>(args)...); 
}
 
template<auto n> // C++17 auto 形参声明
auto f() -> std::pair<decltype(n), decltype(n)> // auto 不能从花括号初始化器列表推导
{
    return {n, n};
}
 
int main()
{
    auto a = 1 + 2;            // a 的类型是 int
    auto b = add(1, 1.2);      // b 的类型是 double
    static_assert(std::is_same_v<decltype(a), int>);
    static_assert(std::is_same_v<decltype(b), double>);
 
    decltype(auto) c1 = a;   // c1 的类型是 int ,保有 a 的副本
    decltype(auto) c2 = (a); // c2 的类型是 int& ,为 a 的别名
    std::cout << "a, before modification through c2 = " << a << '\n';
    ++c2;
    std::cout << "a, after modification through c2 = " << a << '\n';
 
    auto [v, w] = f<0>(); // 结构化绑定声明
 
    auto d = {1, 2}; // OK : d 的类型是 std::initializer_list<int>
    auto n = {5};    // OK : n 的类型是 std::initializer_list<int>
//  auto e{1, 2};    // C++17 起错误,之前为 std::initializer_list<int>
    auto m{5};       // OK : C++17 起 m 的类型为 int ,之前为 initializer_list<int>
//  decltype(auto) z = { 1, 2 } // 错误: {1, 2} 不是表达式
 
    // auto 常用于无名类型,例如 lambda 表达式的类型
    auto lambda = [](int x) { return x + 3; };
 
//  auto int x; // 于 C++98 合法, C++11 起错误
//  auto x;     // 于 C 合法,于 C++ 错误
}

可能的输出:

a, before modification through c2 = 3
a, after modification through c2 = 4