如果你直接在头文件里给 static const int 赋值,在每个编译单元里都会生成一个实例,链接时就冲突了。
二、inline 变量:C++17 的救星
C++17 引入了 inline 变量,完美解决这个问题:
1 2 3 4 5 6
// config.h (C++17 优雅方案) structConfig { inlinestaticint version = 1; inlinestaticconstchar* name = "MyApp"; inlinestaticconstexprdouble PI = 3.14159265358979; };
graph LR
A["Config.h 被 #include"] --> B["编译单元1<br/>生成 Config::version 实例"]
A --> C["编译单元2<br/>生成 Config::version 实例"]
A --> D["编译单元3<br/>生成 Config::version 实例"]
B --> E["🔗 链接器"]
C --> E
D --> E
E --> F["✅ 保留一个实例<br/>ODR 问题解决"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#FFDAB9,stroke:#FFAB76,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#FFDAB9,stroke:#FFAB76,color:#333
style E fill:#E8D5F5,stroke:#CE93D8,color:#333
style F fill:#B5EAD7,stroke:#80CBC4,color:#333
原理:inline 变量告诉链接器”多个编译单元可以定义同一个变量,保留一个就行”。
三、inline 的历史:C++98 就有 inline 函数
版本
inline 支持范围
C++98
inline 函数
C++17
inline 变量
C++20
inline 静态成员(与 C++17 等效)
inline 函数从 C++98 就有了,原理类似:允许在头文件中定义,链接时只保留一份实现。
四、constexpr 全面进化
C++14 vs C++17 constexpr 对比
特性
C++11
C++14
C++17
constexpr 函数限制
单一 return 语句
多语句、局部变量
放宽更多
constexpr lambda
❌
❌
✅ 默认constexpr
constexpr if
❌
❌
✅
constexpr 变参模板
❌
❌
✅
constexpr 字符串
❌
❌
✅ (受限)
constexpr lambda:Lambda 也能编译期求值
C++17 开始,所有 lambda 默认就是 constexpr:
1 2 3 4 5 6 7 8 9 10 11
intmain(){ // C++17: lambda 默认 constexpr auto add = [](auto a, auto b) { return a + b; }; // 编译期常量 constexprint result = add(1, 2); static_assert(add(1, 2) == 3, "lambda 计算要正确"); // C++14 需要这样写: // auto add = [](auto a, auto b) constexpr { return a + b; }; }
constexpr 变量模板:数学常数的现代写法
1 2 3 4 5 6 7 8 9 10 11 12
#include<iostream>
template<typename T> constexpr T pi = T(3.14159265358979323846);