Period 是 std::chrono::duration 的第二个模板参数,类型为 std::ratio,仅表示“1 个滴答等于多少秒”,不是单位名称或时间值;它必须是编译期整数比值,参与 duration_cast 的有理数约简,但不引入运行时开销。

Period 是什么,不是什么
Period 是 std::chrono::duration 的第二个模板参数,类型为 std::ratio,它**只表示“1 个滴答(tick)等于多少秒”**,不是单位名称,也不是时间值本身。常见误解是把它当成“毫秒”或“微秒”的别名——其实 milli 只是 ratio 的 typedef,本质仍是分数。
-
ratio<1, 1000>→ 每个滴答 = 1/1000 秒 = 1 毫秒 -
ratio→ 每个滴答 = 60 秒 = 1 分钟 -
ratio<1, 1000000>→ 每个滴答 = 1 微秒 -
ratio→ 每个滴答 = 2 秒(合法但非常规)
Period 不参与运行时计算,完全在编译期求值,因此不会带来任何开销,但一旦写错分子分母顺序(比如把 ratio<1, 1000> 写成 ratio<1000, 1>),会导致单位放大 1000 倍——休眠变成 1 秒还是 1000 秒,全看这里。
为什么不能随便用 double 当 Period
Period 必须是 std::ratio 类型,而 ratio 要求两个模板参数都是编译期整数常量(std::intmax_t)。这意味着:
- ❌
ratio<0.001>编译失败:小数不被接受 - ❌
ratio<1.0, 1000.0>编译失败:非整型 - ✅
ratio<1, 1000>合法,等价于 1/1000 - ✅
ratio<1001, 1000000>也合法(表示 1.001 毫秒),只要分子分母是整数
实际中几乎不会手写非标准比值,因为预定义类型(nanoseconds、milliseconds 等)已覆盖全部常用场景。强行自定义非整数比值,不仅没意义,还会让 duration_cast 在跨精度转换时行为不可预测。
duration_cast 依赖 Period 的隐式约简规则
当用duration_cast 转换单位时,编译器会基于两个 Period 的比值做有理数约简。例如:
-
duration_cast<microseconds>(milliseconds(1))</microseconds>→ratio<1, 1000>÷ratio<1, 1000000>= 1000,结果是microseconds(1000) -
duration_cast<seconds>(minutes(1))</seconds>→ratio÷ratio= 60,结果是seconds(60)
但若 Period 无法整除(比如把 ratio 的 duration 转成 seconds),duration_cast 会向零截断(truncates toward zero),不是四舍五入:
using custom = duration<int, ratio<3>>; // 每 tick = 3 秒 auto d = custom(5); // 表示 15 秒 auto s = duration_cast<seconds>(d); // 结果是 seconds(15),没问题 auto ms = duration_cast<milliseconds>(d); // 15 秒 → 15000 毫秒,也没问题 auto half_sec = duration_cast<duration<int, ratio<1, 2>>>(d); // 每 tick = 0.5 秒 → 15 秒 = 30 ticks,结果是 duration<...>(30)
关键点在于:所有转换都基于精确的有理数运算,但最终 count() 返回整型,小数部分永远丢失。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
自定义 Period 的真实使用场景极少
除非你在嵌入式系统里对接某个硬件定时器,其计数周期是 17.3 µs 这种非标值,否则没必要碰ratio。即便如此,也建议用 ratio(即 173/10000000 秒 ≈ 17.3 ns?注意单位换算),而不是试图用浮点逼近。
更现实的做法是:
- 用
nanoseconds存原始计数,最后再按需转成业务单位(如“每帧 16.666… ms”) - 若真需非标单位,优先封装成新类型别名,而非裸写
ratio:using frame_time = duration<int64_t, ratio<1, 60>>; // 1/60 秒,适合 60fps 场景
真正容易被忽略的是:Period 和 Rep 共同决定数值范围。比如 duration<char, milli> 最多只能存 127 毫秒——char 溢出比你想象中快得多。

















