std::ratio是编译期有理数模板,用于精确表示分子/分母比例(如std::ratio<1,1000>),本身不处理时间;C++用它定义std::chrono::duration的精度,如std::milli即std::ratio<1,1000>别名。

std::ratio 是什么,它和时间单位有啥关系
std::ratio 本身不处理时间,也不依赖 <chrono>;它只是编译期有理数模板,用于表示分子/分母形式的精确比例(比如 std::ratio<1, 1000> 表示千分之一)。C++ 标准库用它来定义 std::chrono::duration 的精度,比如 std::milli 就是 std::ratio<1, 1000> 的别名。
你不能直接拿 std::ratio 当“时间类型”用——它没构造函数、没值、不存数据,只提供 num 和 den 静态成员。真正做时间运算得靠 std::chrono::duration + std::ratio 作为模板参数。
怎么用 std::ratio 定义自定义时间单位
比如你要一个“微世纪”(microcentury),即一百万分之一世纪(1 世纪 = 100 年 ≈ 3.15576e9 秒),就得先算出等效秒数比例,再约分成最简整数比:
constexpr auto microcentury = std::chrono::duration<long long, std::ratio<315576, 100>>{};
但更稳妥的做法是基于已知单位推导:
立即学习“C++免费学习笔记(深入)”;
-
std::chrono::hours是std::duration<int, std::ratio<3600>> - 想定义“半分钟”,就写
std::chrono::duration<int, std::ratio<30>> - 想定义“1/7 秒”,必须用
std::ratio<1, 7>,不能写std::ratio<0.142857, 1>(num/den必须是整型常量表达式)
注意:所有 std::ratio 参数在编译期就必须确定,且 den 不能为 0;除法会自动约分(std::ratio<2, 4> 等价于 std::ratio<1, 2>)。
常见错误:把 ratio 当数值用或混用浮点
下面这些写法都会编译失败:
-
auto r = std::ratio<1, 3>{};——std::ratio没默认构造函数,不能实例化 -
std::ratio<1.0, 3>——num和den必须是整型字面量 -
std::chrono::duration<float, std::ratio<1, 3>> d = 1.0;—— 虽然能编译,但除法结果可能因 float 精度丢失(比如 1/3 不精确),应优先用整型 + 更大rep类型(如long long)
真正需要非整数比例时(比如 1/π 秒),std::ratio 无能为力,得换用 std::chrono::duration<double, std::ratio<1>> 并接受浮点误差。
ratio 的约分和溢出风险
std::ratio 在编译期自动约分,但分子分母过大时可能触发整型溢出(尤其在 MSVC 或旧 GCC 上):
-
std::ratio<1000000000000000000LL, 1>可能因字面量超出long范围报错 -
std::ratio<1, 1000000000000000000LL>同样危险,某些标准库实现会在约分过程中临时计算gcd导致中间值溢出 - 安全做法:用标准预定义别名(
std::nano,std::micro等),或确保num/den在long long范围内且互质
实际项目里,除非对接硬件计时器要求特殊分频比,否则别手写大数字 std::ratio——容易白忙活半天还编译不过。


















