1. auto
是什么?
一句话:
让编译器帮你看一眼"右边是什么类型",然后自动把变量声明成那个类型。
cpp
auto x = 42; // 右边是 int 字面量 -> x 的类型就是 int
auto y = 3.14; // 右边是 double 字面量 -> y 就是 double
auto z = "hello"; // 右边是 const char* -> z 就是 const char*
写起来像动态语言(Python/JavaScript),但编译期就确定了具体类型,所以不会损失性能。
2. 基本语法
语法模板:
arduino
auto 变量名 = 初始值; // 必须有初始值,否则编译器没法推断
注意:
- 不能写成
auto x;
------ 会报错! - 可以加上
const
、&
、*
等修饰符,写法如下:
cpp
const auto a = 10; // const int
auto& b = a; // 引用,类型是 const int&
auto* p = &a; // 指针,类型是 const int*
3. 常见场景逐个击破
3.1 迭代器------最常用
传统写法又长又臭:
cpp
std::map<std::string, std::vector<int>> m;
// 传统写法
for (std::map<std::string, std::vector<int>>::iterator it = m.begin();
it != m.end(); ++it) { ... }
auto
写法:
cpp
for (auto it = m.begin(); it != m.end(); ++it) { ... }
再升级(C++11 range-for):
cpp
for (const auto& kv : m) {
// kv.first -> std::string
// kv.second -> std::vector<int>
}
3.2 返回值类型很长
cpp
std::shared_ptr<std::unordered_map<int, std::string>>
createTable(); // 返回类型巨长
auto table = createTable(); // 一行搞定
3.3 泛型代码 / 模板
cpp
template<typename Container>
void printFirst(const Container& c) {
auto it = c.begin(); // 不用关心 Container 是什么
if (it != c.end())
std::cout << *it;
}
4. 容易被坑的 3 个细节
4.1 忘记引用导致拷贝
cpp
std::vector<int> v = {1,2,3};
for (auto x : v) x *= 2; // 改的是拷贝,原 vector 不变
for (auto& x : v) x *= 2; // OK,改的是原数据
4.2 类型推断与"顶层 const"被丢弃
cpp
const int ci = 100;
auto a = ci; // a 是 int,顶层 const 被丢掉
auto& b = ci; // b 是 const int&,保留底层 const
4.3 auto
不能用来推导数组
cpp
int arr[5];
auto a = arr; // a 退化成 int*,不是 int[5]
5. C++14/C++17 加强补充(了解即可)
-
返回值自动推导(C++14)
cppauto add(int x, int y) { return x + y; } // 编译器自己看 return 语句
-
泛型 lambda(C++14)
cppauto lambda = [](auto x, auto y) { return x + y; };
-
结构化绑定(C++17)
cppstd::map<int, std::string> mp; for (const auto& [key, val] : mp) { ... } // 直接解包 key 和 val
6. 一张思维导图(文字版)
arduino
auto
├─ 基本:auto x = 初始值;
├─ 修饰:const auto&, auto*, ...
├─ 场景
│ ├─ 迭代器
│ ├─ 返回值
│ ├─ 模板 / 泛型
│ └─ lambda
└─ 坑
├─ 忘引用
├─ const 被丢
└─ 数组退化
7. 小结口诀(背下来)
"右边是啥我就啥,必须初始化;引用加 &,只读加 const,别忘范围 for 用 &!"