std::numbers 提供 pi、e、sqrt2、ln2、phi 等 constexpr 数学常量,均为变量模板,须用 _v<T> 形式访问(如 std::numbers::pi_v<double>),C++20 起可用,需显式启用 -std=c++20。

std::numbers 里有哪些可用的数学常量
std::numbers 是 C++20 引入的头文件 <numbers> 中的命名空间,专门提供标准化的数学常量。它不是宏或全局变量,而是 constexpr 变量模板,类型精确(比如 double、float、long double),且保证在编译期可用。
常见常量包括:pi、e、sqrt2、ln2、phi(黄金比例)等,每个都带类型后缀,例如:
std::numbers::pi_v<double> // 默认推荐,等价于 std::numbers::pi std::numbers::pi_v<float> std::numbers::pi_v<long double>
注意:没有裸名如 std::numbers::pi(那只是变量模板名),必须用 _v 后缀或显式指定模板参数才能取值。
为什么不能直接写 std::numbers::pi
因为 std::numbers::pi 是一个变量模板(variable template),不是具体值。C++ 要求你明确告诉编译器要哪个精度版本——这避免了隐式转换带来的精度丢失或重载歧义。
立即学习“C++免费学习笔记(深入)”;
常见错误现象:
- 编译报错:
error: expected a type或error: use of undeclared identifier 'pi'(忘了加_v<T>) - 链接失败或未定义引用(误以为它是宏或普通 extern 变量)
- 数值意外截断(比如用
float计算却取了double版本再隐式转)
正确写法只有两种:
-
std::numbers::pi_v<double>(显式指定) -
std::numbers::pi(不推荐!这是 C++23 才允许的简写,C++20 不支持)
使用前必须包含 <numbers> 且确认标准版本
<numbers> 是 C++20 新增头文件,旧标准(C++17 及以前)不提供。即使编译器支持部分 C++20 特性,也可能默认不启用该头文件。
确保构建配置满足以下条件:
- 编译器支持:GCC 11+、Clang 12+、MSVC 19.30+(VS 2022 17.0+)
- 显式开启 C++20:编译时加
-std=c++20(GCC/Clang)或/std:c++20(MSVC) - 头文件路径正确,不依赖
<cmath>或<math.h>——它们不声明std::numbers
如果仍报 fatal error: numbers: No such file or directory,大概率是标准版本没设对,而不是头文件缺失。
和传统 M_PI 等宏相比有什么实际影响
M_PI 来自 C 标准库(<cmath> 或 <math.h>),但它是非标准扩展,POSIX 定义、C++ 标准不保证存在。不同平台、不同编译器宏开关(如 _USE_MATH_DEFINES)行为不一致。
用 std::numbers 的实际好处:
- 可移植性强:只要 C++20 编译器就一定有
std::numbers::pi_v<double> - 类型安全:不会因宏展开导致整型上下文误用(比如
int x = M_PI;静默截断) - constexpr 友好:能用于模板非类型参数、数组大小、
static_assert等场景 - 无宏污染:不依赖预处理器,不会和用户定义的
pi名称冲突
性能上无差异——所有值都是编译期常量,汇编输出完全一致。真正容易被忽略的是:它只解决「常量定义」问题,不提供计算函数(比如 sin、log 还得靠 <cmath>)。


















