auto (C++)

从其初始化表达式中推导声明的变量的类型。

注意

C++ 标准为此关键字定义了初始和修订的含义。 在 Visual Studio 2010 之前,auto 关键字在自动存储类中声明变量;即,具有局部生存期的变量。 从 Visual Studio 2010 开始,关键字 auto 声明其类型从其声明中的初始化表达式推导出的变量。 /Zc:auto[-] 编译器选项控制 auto 关键字的意义。

语法

autodeclaratorinitializer;

[](autoparam1, autoparam2) {};

备注

auto 关键字指示编译器使用已声明变量的初始化表达式或 lambda 表达式参数来推导其类型。

在大多情况下,建议使用 auto 关键字(除非确实需要转换),因为此关键字具有以下好处:

  • 可靠性:如果表达式的类型发生更改(包括函数返回类型发生更改的情况),它也能工作。

  • 性能:确保不会进行转换。

  • 可用性:不必担心类型名称拼写困难和拼写有误。

  • 效率:代码会变得更高效。

可能不需要使用 auto 的转换情况:

  • 你需要一个特定类型,任何其他类型都不行。

  • 例如,在表达式模板帮助程序类型 (valarray+valarray) 中。

若要使用 auto 关键字,请使用它而不是类型来声明变量,并指定初始化表达式。 此外,还可通过使用说明符和声明符(如 constvolatile)、指针 (*)、引用 (&) 以及右值引用 (&&) 来修改 auto 关键字。 编译器计算初始化表达式,然后使用该信息来推断变量类型。

auto 初始化表达式可以采用多种形式:

  • 通用初始化语法,例如 auto a { 42 };
  • 赋值语法,例如 auto b = 0;
  • 通用赋值语法,它结合了上述两种形式,例如 auto c = { 3.14159 };
  • 直接初始化或构造函数样式的语法,例如 auto d( 1.41421f );

有关详细信息,请参阅初始值设定项和本文档后面的代码示例。

auto 用于在基于范围的 for 语句中声明循环参数时,它使用不同的初始化语法,例如for (auto& i : iterable) do_action(i);。 有关详细信息,请参阅基于范围的 for 语句 (C++)

auto 关键字是类型的占位符,但它本身不是类型。 因此,auto 关键字不能用于强制转换或运算符,如 sizeof 和(用于 C++/CLI)typeid

有用性

auto 关键字是声明复杂类型变量的简单方法。 例如,可使用 auto 声明一个变量,其中初始化表达式涉及模板、指向函数的指针或指向成员的指针。

也可使用 auto 声明变量并将其初始化为 lambda 表达式。 您不能自行声明变量的类型,因为仅编译器知道 lambda 表达式的类型。 有关详细信息,请参阅 Lambda 表达式示例

尾部的返回类型

您可将 autodecltype 类型说明符一起使用来帮助编写模板库。 使用 autodecltype 声明其返回类型取决于其模板自变量类型的函数模板。 或者,使用 autodecltype 声明函数模板,该模板包装对其他函数的调用,然后返回任何返回类型的其他函数。 有关详细信息,请参阅 decltype

引用和 cv 限定符

使用 auto 会删除引用、const 限定符和 volatile 限定符。 请考虑以下示例:

// cl.exe /analyze /EHsc /W4
#include <iostream>

using namespace std;

int main( )
{
    int count = 10;
    int& countRef = count;
    auto myAuto = countRef;

    countRef = 11;
    cout << count << " ";

    myAuto = 12;
    cout << count << endl;
}

在前面的示例中,myAuto 是 int,而不是引用 int,因此,如果引用限定符尚未被 auto 删除,则输出为 11 11 而不是 11 12

使用括号初始值设定项 (C++14) 的类型推导

下面的代码示例演示如何使用大括号初始化 auto 变量。 请注意 B 和 C 与 A 与 E 之间的差异。

#include <initializer_list>

int main()
{
    // std::initializer_list<int>
    auto A = { 1, 2 };

    // std::initializer_list<int>
    auto B = { 3 };

    // int
    auto C{ 4 };

    // C3535: cannot deduce type for 'auto' from initializer list'
    auto D = { 5, 6.7 };

    // C3518 in a direct-list-initialization context the type for 'auto'
    // can only be deduced from a single initializer expression
    auto E{ 8, 9 };

    return 0;
}

限制和错误消息

下表列出了使用 auto 关键字的限制,及编译器发出的相应诊断错误消息。

错误号 说明
C3530 auto 关键字不能与任何其他类型说明符组合。
C3531 使用 auto 关键字声明的符号必须具有初始值设定项。
C3532 你错误地使用了 auto 关键字来声明类型。 例如,声明了方法返回类型或数组。
C3533C3539 不能使用 auto 关键字声明参数或模板自变量。
C3535 不能使用 auto 关键字声明的方法或模板自变量。
C3536 符号初始化之前无法使用。 在实践中,这意味着无法使用变量来初始化自身。
C3537 无法强制转换为使用 auto 关键字声明的类型。
C3538 使用 auto 关键字声明的声明符列表中的所有符号必须解析为相同的类型。 有关详细信息,请参阅声明和定义
C3540C3541 sizeoftypeid 运算符不能应用于使用 auto 关键字声明的符号。

示例

这些代码片段阐释了可使用 auto 关键字的一些方法。

下面的声明等效。 在第一个语句中,将变量 j 声明为类型 int。 在第二个语句中,将变量 k 推导为类型 int,因为初始化表达式 (0) 是整数。

int j = 0;  // Variable j is explicitly type int.
auto k = 0; // Variable k is implicitly type int because 0 is an integer.

以下声明等效,但第二个声明比第一个更简单。 使用 auto 关键字的最令人信服的一个原因是简单。

map<int,list<string>>::iterator i = m.begin();
auto i = m.begin();

for 和范围 for 循环启动时,下列代码片段将声明变量 iterelem 的类型。

// cl /EHsc /nologo /W4
#include <deque>
using namespace std;

int main()
{
    deque<double> dqDoubleData(10, 0.1);

    for (auto iter = dqDoubleData.begin(); iter != dqDoubleData.end(); ++iter)
    { /* ... */ }

    // prefer range-for loops with the following information in mind
    // (this applies to any range-for with auto, not just deque)

    for (auto elem : dqDoubleData) // COPIES elements, not much better than the previous examples
    { /* ... */ }

    for (auto& elem : dqDoubleData) // observes and/or modifies elements IN-PLACE
    { /* ... */ }

    for (const auto& elem : dqDoubleData) // observes elements IN-PLACE
    { /* ... */ }
}

下面的代码片段使用 new 运算符和指针声明来声明指针。

double x = 12.34;
auto *y = new auto(x), **z = new auto(&x);

下一个代码片段在每个声明语句中声明多个符号。 请注意,每个语句中的所有符号将解析为同一类型。

auto x = 1, *y = &x, **z = &y; // Resolves to int.
auto a(2.01), *b (&a);         // Resolves to double.
auto c = 'a', *d(&c);          // Resolves to char.
auto m = 1, &n = m;            // Resolves to int.

此代码片段使用条件运算符 (?:) 将变量 x 声明为值为 200 的整数:

int v1 = 100, v2 = 200;
auto x = v1 > v2 ? v1 : v2;

下面的代码片段将变量 x 初始化为类型 int,将变量 y 初始化对类型 const int 的引用,将变量 fp 初始化为指向返回类型 int 的函数的指针。

int f(int x) { return x; }
int main()
{
    auto x = f(0);
    const auto& y = f(1);
    int (*p)(int x);
    p = f;
    auto fp = p;
    //...
}

另请参阅

关键字
/Zc:auto(推导变量类型)
sizeof 运算符
typeid
operator new
声明和定义
Lambda 表达式的示例
初始值设定项
decltype