std::ratio 是编译期有理数模板,用于 constexpr 精确表示分数,无运行时开销;仅含静态常量 num 和 den,支持 ratio_add 等元运算,常用于 chrono 时间单位定义。

std::ratio 是什么,它根本不是运行时类型
它是一套编译期有理数模板,用来在 constexpr 上下文中精确表示分数(比如 1/1000、1024/1),不占运行时内存,也不产生任何指令。你不能对它做 std::ratio r = ...; 这种赋值——它没有构造函数,没有数据成员,只有两个公开的静态常量 num 和 den。
怎么定义和使用 std::ratio
直接用模板参数写分子分母,比如 std::ratio 表示千分之一;std::ratio 等价于 std::ratio。它本身不提供计算能力,但标准库配套提供了 std::ratio_add、std::ratio_multiply 等元函数,用于编译期算术:
using ms = std::ratio<1, 1000>; using s = std::ratio<1>; using us = std::ratio_multiply>; // 1 微秒 = 1ms × 1/1000
-
std::ratio的分子分母必须是整型字面量,且分母不能为 0;否则编译失败,错误信息类似static_assert failed due to requirement 'Den != 0' - 分子分母会自动约分:
std::ratio等价于std::ratio,这是通过std::gcd在编译期完成的 - 所有运算结果仍是
std::ratio类型,仍可继续参与元运算,但无法直接转成浮点数——你得手动取num/den再算
它最常出现在 chrono 里,别想绕开它
std::chrono::duration 的第二个模板参数就是 std::ratio,比如 std::chrono::milliseconds 底层就是 duration。如果你自己定义时间单位,漏掉或写错 ratio,就会触发类型不匹配:
auto d = std::chrono::seconds(5); // 错误:不能把 duration<…, ratio<1>> 隐式转成 duration<…, ratio<1,1000>> std::chrono::milliseconds ms = d; // 编译失败
- 跨单位赋值需显式转换:
std::chrono::milliseconds ms = std::chrono::duration_cast<:chrono::milliseconds>(d); - 自定义单位时,别手写大数分母(如
std::ratio),优先用std::nano、std::pico这类标准别名,它们更易读且已约分 -
std::ratio不支持负数分子(C++17 起允许,但很多老编译器仍报错),要表示负向偏移,用-std::ratio::num手动处理
为什么不能用 float 或 double 替代
因为浮点数在编译期不可 constexpr(C++20 前),且存在精度丢失:比如 1.0/1000.0 在二进制下是无限循环小数。而 std::ratio 是精确、无损、纯整型的——它存在的唯一目的,就是让“1 毫秒 = 1/1000 秒”这种关系,在编译器眼里是铁律,不是近似值。
立即学习“C++免费学习笔记(深入)”;
真正容易被忽略的是:它的所有能力都锁死在模板实例化阶段。一旦进入运行时(比如用户输入一个分母),你就没法再构造新的 std::ratio ——这时候只能退回到浮点或自定义有理数类。









