auto 是C++的关键字特性,在C++11以前,仅仅作为“存储类说明符”,用于表示“自动存储期”的变量,没有实际应用意义:
C++
auto int x = 5; // 等价于 int x = 5;auto表示变量在进入作用域时自动分配,离开作用域时自动销毁- 由于局部变量默认就是自动存储期,所以这个关键字几乎从不使用
- 用法继承自 C 语言
自C++11开始,auto 关键字变成C++现代编程中重要的关键字特性,其功能应用发生重要变化——类型推导。
C++
std::vector<int> vec = {1, 2, 3};
auto it = vec.begin();
// it 推导为 std::vector<int>::iterator
std::map<std::string, int> m;
auto pair = m.begin();
// pair 推导为 std::map<std::string, int>::iteratorC++14中,auto 可以进行函数返回类型与Lambda 参数类型推导,同时支持 decltype(auto)。
C++
// C++11 需要指定具体类型
auto lambda = [](int x) { return x * 2; };
// C++14 可以使用 auto
auto generic_lambda = [](auto x, auto y) {
return x + y; // 支持任意类型
};
generic_lambda(3, 4); // 返回 7
generic_lambda(3.5, 2.5); // 返回 6.0
//decltype(auto)
int x = 10;
int& get_ref() { return x; }
auto a = get_ref(); // a 是 int(值类型)
decltype(auto) b = get_ref(); // b 是 int&(引用类型)C++17进一步扩展,主要为结构化绑定。
C++
std::pair<int, std::string> p = {1, "hello"};
auto [id, name] = p; // id 推导为 int,name 推导为 std::string
std::map<int, std::string> m = {{1, "one"}, {2, "two"}};
for (const auto& [key, value] : m) {
// key 是 const int,value 是 const std::string&
}C++20中 auto 修饰函数中形式参数,与C++14中 lambda 的 auto 应用类似。
C++
// 传统模板
template<typename T>
void print(const T& value) {
std::cout << value << std::endl;
}
// C++20 使用 auto
void print(const auto& value) {
std::cout << value << std::endl;
}
// 也可以用于多个参数
auto add(auto a, auto b) { // 每个 auto 都是独立的模板参数
return a + b;
}C++20中还添加了概念约束的 auto 特性,简单来说就是对传统的泛型编程进行增强与限制,使 auto 关键字的使用符合预期的同时,实现更精确的接口约束,提供更好的代码可读性。
std::integral | 整数类型 | int, long, char |
std::floating_point | 浮点类型 | float, double |
std::copyable | 可复制 | 大多数类 |
std::movable | 可移动 | 大多数类 |
std::equality_comparable | 可比较相等性 | 有 == 操作符的类型 |
std::totally_ordered | 可全序比较 | 有 ==, !=, <, >, <=, >= |
std::invocable | 可调用 | 函数、lambda、函数对象 |
std::range | 范围 | 容器、视图 |
C++
// C++20 之前:需要复杂的 SFINAE 或 static_assert
template<typename T>
void print(const T& value) {
static_assert(/* 复杂的类型检查 */);
std::cout << value << std::endl;
}
// C++20:使用概念约束
void print(const std::output_streamable auto& value) {
std::cout << value << std::endl;
}对 auto 关键字的一些思考:
- 按照朴素认知,这种自动化的类型转换总感觉是不安全的,但实际上
auto关键字在C++中的应用是极其安全且普适的。主要原因是C++为静态编译语言,即auto关键字修饰的变量在运行之前会先进行编译,一旦编译器确定了类型,这个变量的类型就固定了,后续任何不匹配的操作依然会导致编译错误。 - 同时,该操作不涉及任何隐形的类型转换或性能损耗,它只是让编译器帮你写代码,而不是让程序在运行时乱跑。
-
auto并不是“放弃了类型检查”,而是“把类型检查交给了最不会犯错的编译器”。它在保证静态类型安全的前提下,减少了代码冗余,并强制要求初始化。
//关于各编程语言对比放后面再研究。
auto 的最佳实践与建议:
1.迭代器和复杂类型:
C++
for (auto it = vec.begin(); it != vec.end(); ++it)2.范围 for 循环
C++
for (const auto& item : container)3.避免类型冗长
C++
auto result = some_complex_function();4.Lambda 表达式
C++
auto lambda = [](int x) { return x * 2; }; auto 避免滥用:简单类型、需显式给出的类型、使用会严重影响可读性的场景等。