C++ auto 关键字

平时定义变量时,我们通常都需要在变量名前面明确写出 int、double、char 等类型名。

从 C++11 标准开始,auto 关键字拥有了全新的作用。其中,auto 是英文 “automatic(自动)” 的缩写:定义变量时可以直接写上 auto,让编译器根据等号右边的初始值自动推导出变量的数据类型。

C++ auto 基本用法

在 C++ 中,使用 auto 定义变量非常简单,只需要把原本写 int、double 等类型名的位置替换成 auto 即可。

语法:

auto 变量名 = 初始值;

说明:

当编译器看到 auto 时,会自动检查等号(=)右边的初始值或表达式是什么类型,然后把左边变量的类型确定下来。常见初始值对应的 auto 推导结果如下表所示。

auto 常见类型推导
代码示例 右侧初始值 推导出的类型
auto count = 10; 整数字面量 10 int
auto big = 100LL; 带 LL 后缀的整数 long long
auto price = 19.8; 浮点数字面量 19.8 double
auto grade = 'A'; 字符字面量 'A' char
auto finished = true; 布尔字面量 true bool

这里需要注意一点:使用 auto 之后,变量的数据类型并没有消失,只是从 “我们手动写出来” 变成了 “编译器自动推导出来”。

示例 1:使用 auto 定义变量

#include <iostream>

int main() {
    auto count = 10;
    auto big = 8100000000LL;
    auto price = 19.8;
    auto grade = 'A';

    std::cout << count << ' ' << big << '\n';
    std::cout << price << ' ' << grade << '\n';
    return 0;
}

运行结果如下。

10 8100000000
19.8 A

分析:

在这个例子中,编译器根据每一行等号右边的字面量,分别将 count 推导为 int、将带 LL 后缀的 big 推导为 long long、将 price 推导为 double、将 grade 推导为 char。推导完成后,这些变量的使用方式与直接写出类型名完全一样。

除了单个字面量之外,如果等号右边是一条算术表达式,auto 同样会根据整个表达式最终算出的结果类型来推导变量类型。请看下面例子。

示例 2:根据表达式推导类型

#include <iostream>

int main() {
    int distance = 25;
    int time = 4;

    auto speed1 = distance / time;
    auto speed2 = static_cast<double>(distance) / time;

    std::cout << speed1 << '\n';
    std::cout << speed2 << '\n';
    return 0;
}

运行结果如下。

6
6.25

分析:

这里把前面学过的整数除法、类型转换与 auto 结合在了一起:计算 speed1 时,等号右边的 distance / time 是两个 int 相除,算出的结果是 int 类型的整数 6,因此 speed1 自动推导为 int 类型。

计算 speed2 时,右边先通过 static_cast<double> 把 distance 转成了 double,算出 double 类型的 6.25,因此 speed2 自动推导为 double 类型。简单来说,右边表达式最终算出什么类型,左边变量就是什么类型。

提示 如果需要定义一个值不能修改的常量,auto 也可以和 const 搭配使用,比如写成 const auto PI = 3.14;,编译器会自动将其推导为只读的 const double 类型。

使用 auto 的注意事项

在使用 auto 定义变量时,有 2 条语法规则需要小伙伴们重点掌握,下面我们结合示例来看。

1. 定义时必须初始化

普通变量像 int value; 这样可以先定义、不赋初值,等到后面再通过 value = 10; 赋值。但如果使用 auto 定义变量,就必须在定义的同时赋上初始值,否则程序无法通过编译。

示例 3:未初始化导致报错

#include <iostream>

int main() {
    auto value;
    value = 10;
    std::cout << value << '\n';
    return 0;
}

运行结果如下。

(报错)error: declaration of 'auto value' has no initializer

分析:

为什么 auto value; 会直接报错呢?报错信息的意思是声明 auto value 时没有赋初始值。写 int value; 时,我们已经明确告诉了编译器这是一个 int 变量。而写 auto value; 时,等号右边没有任何初始值,编译器没有依据去推导 value 是什么类型,自然也没法分配内存。

另外还要留意一点:如果在同一行里使用 auto 同时定义多个变量,它们的初始值推导出的类型必须一致。下面这种一个赋整数、一个赋小数的写法,编译器同样会直接报错:

auto a = 10, b = 3.14;    // 推导出的类型不一致

2. 推导后类型固定不变

有些学过 Python 或 JavaScript 的小伙伴,看到 auto 容易产生一个疑问:“auto 变量是不是可以随时变换类型,一会儿存整数,一会儿存小数?”

实际上,这样理解是不正确的。C++ 是一门静态类型语言,auto 只负责在变量定义的那一刻推导一次类型。一旦变量的类型确定下来,直到程序结束都不会再改变。下面我们来看一个例子。

示例 4:推导后类型不会改变

#include <iostream>

int main() {
    auto count = 10;
    count = 3.8;
    std::cout << count << '\n';
    return 0;
}

运行结果如下。

3

分析:

从运行结果可以看出,count = 3.8; 执行后,打印出来的结果是 3 而不是 3.8。对于这个例子来说,上面代码等价于下面两步:

int count = 10;    // 类型已固定为 int
count = 3.8;       // 小数部分截断,结果变成 3

可以看到,auto 并不是动态类型。变量 count 在定义时根据 10 推导为 int 之后,就已经是一个普普通通的 int 变量了,后续把 3.8 赋给它时,依然会按 int 变量的规则直接抹去小数部分。

何时适合使用 auto?

学会了 auto 之后,是不是以后定义所有变量都写成 auto 最好呢?恰恰相反,在实际开发中,我们应该根据代码的可读性来决定是否使用 auto:

  • 简单基础变量直接写明类型:像 int count = 10; 或 double price = 19.8; 这类基础变量,类型名本来就很简短,直接写出 int 或 double 能让读代码的人一眼看清类型,没有必要全部改成 auto。
  • 右侧已体现类型或类型名较长时使用 auto:当等号右边已经明确写出了目标类型,比如使用了 static_cast<double>,或者遇到名字很长的复杂类型时,使用 auto 可以省去重复书写类型名的麻烦。

我们可以对比一下下面这两种写法:

// 不推荐
auto count = 10;

// 推荐
int count = 10;
auto average = static_cast<double>(total) / count;

总而言之,选择 “直接写类型名” 还是 “写 auto” 的判断标准其实只有一条:直接写类型名更直观时,就写类型名。当类型名太长或等号右边已经写明类型时,就使用 auto 简化代码。

常见问题

1. 如果写 auto name = "Jack";,推导出来的是 std::string 字符串类型吗?

并不是。在 C++ 中,直接用双引号括起来的 "Jack" 默认属于传统的 C 风格字符串,因此 auto 推导出来的并不是 std::string 字符串类型。

现阶段我们在整数、小数、字符和布尔值上使用 auto 最稳妥,等学完字符串章节后再结合字符串一起使用即可。

上一篇:

下一篇:

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号