C++ 杂记之一从基础到进阶

auto 关键字

auto 是 C++ 中的一个关键字,用于让编译器自动推导变量的类型(自动类型推导),从而使代码更简洁、灵活,减少重复声明类型的麻烦。它在 C++11 中首次引入,并在 C++14、C++17 中得到了进一步增强。

auto 核心概念

  • auto 的基础语法: auto 变量名 = 初始值;
  • auto 可以根据初始化表达式,自动推导变量的类型,无需显式写出类型。
  • auto 必须在声明时初始化,因为编译器需要通过初始值推导具体的类型。
  • auto 的自动类型推导发生在编译期间,因此使用 auto 不会影响程序的运行效率。
  • auto 支持泛型、模板编程等现代 C++ 风格,常用于范围 for 和 Lambda 表达式中。

auto 使用场景

  • 简单类型声明
1
auto x = 10;
  • 简化复杂类型声明
1
2
3
std::map<std::string, std::vector<int>>::iterator it = myMap.begin();

auto it = myMap.begin(); // 使用 auto 简洁很多
  • 与范围 for 搭配使用
1
2
3
4
5
std::vector<int> vec = {1, 2, 3};

for (auto val : vec) {
std::cout << val << std::endl;
}
  • Lambda 表达式和模板返回值推导
1
auto add = [](int a, int b) { return a + b; };

auto 功能增强

  • C++14 的增强:auto 可以用于函数返回类型
1
2
3
auto add(int a, int b) {
return a + b; // 返回类型自动推导为 int
}
  • C++20 的增强:auto 可以用于范围推导(简化结构绑定)
1
2
std::pair<int, std::string> p = {1, "hello"};
auto [id, name] = p;

auto 使用注意事项

  • 必须在声明时初始化
1
auto x;     // 错误写法:没有初始值,编译器无法推导类型
  • 推导的是值类型
1
2
3
4
5
int x = 5;
int& ref = x;
auto a = ref; // a 是 int,不是 int&

auto& b = ref; // 若想保留引用,需要显式声明,b 是 int&,会改变 x
  • const 会被保留 / 去除
1
2
3
4
const int ci = 100;

auto a = ci; // a 是 int,去掉了 const
auto& b = ci; // b 是 const int&,保留了 const

constexpr 关键字

constexpr 简介

constexpr 是 C++ 11 引入的一个关键字,表示 编译时常量表达式。它用于指示编译器:一个变量、函数或构造函数的值可以在编译期间求值,从而实现更高效的代码(例如:避免运行时计算、提升性能、在模板中使用等)。

constexpr 变量

  • constexpr 变量表示这个变量的值在编译时就已知,类似 const,但更强:
1
2
constexpr int size = 10;  // 编译期常量
int arr[size]; // 可以作为数组大小
  • constexpr 区别于 const
1
2
3
4
const int a = rand();       // 编译通过,但不是编译期常量

constexpr int b = rand(); // 编译失败,不是编译期常量
constexpr int c = 3 + 4; // 编译通过,是编译期常量

constexpr 函数

  • constexpr 函数表示用于定义可以在编译期执行的函数,在 C++ 11 中其定义规则:(1) 函数体必须只有一个 return 表达式; (2) 所有参数和调用都必须是常量表达式;
1
2
3
4
5
constexpr int square(int x) {
return x * x;
}

int arr[square(4)]; // 编译通过,square(4) 在编译期间计算结果为 16
  • 从 C++ 14 开始,constexpr 函数可以有:多条语句、条件判断(if)、循环(forwhile
1
2
3
4
5
6
7
8
// C++14 及以后支持的写法
constexpr int factorial(int n) {
int res = 1;
for (int i = 1; i <= n; ++i) {
res *= i;
}
return res;
}

constexpr 构造函数

从 C++ 11 开始,可以将一个类的构造函数定义为 constexpr,使得该类可以在编译期构造对象:

1
2
3
4
5
6
7
8
9
10
11
12
class Point {
public:
constexpr Point(int x_, int y_) : x(x_), y(y_) {

}

private:
int x, y;
};

constexpr Point p1(1, 2); // p1 为编译期对象

constexpr 应用场景

场景用途
定义静态数组大小constexpr int size = 100; int arr[size];
作为模板参数template<int N> struct Array {}
提高性能避免运行时计算,提升速度
switch 中使用case square(3):
元编程templatetype_traits 等结合实现复杂编译期计算

constexpr 使用注意事项

  • constexpr 不等于 “只在编译期计算”,它也可以在运行期使用,只是如果传入常量,它可以在编译期计算。
  • 从 C++ 20 起,constexpr 支持的功能更强,几乎可用于所有逻辑控制(包括 try/catch 限制性支持)。
  • constexprconstevalconstinit 是不同的概念(见下表)。

constexpr 与相关关键字对比

关键字引入版本含义
constC++ 98 值不可变(可用于编译期或运行期常量)
constexprC++ 11 编译期可求值的常量或函数(从 C++ 14 开始支持更复杂的函数体)
constevalC++ 20 必须在编译期计算的函数(调用时就会被立即求值)
constinitC++ 20 保证用于初始化 staticthread_local 变量时没有静态初始化顺序问题