这些是std::chrono::duration 构造函数的 gcc/libstdc++ 实现。我们可以一次看一个:
template <typename _Rep2,
typename = typename enable_if
<
is_convertible<_Rep2, rep>::value &&
(treat_as_floating_point<rep>::value ||
!treat_as_floating_point<_Rep2>::value)
>::type>
constexpr
explicit
duration(const _Rep2& __rep)
: __r(static_cast<rep>(__rep))
{ }
格式化有助于提高可读性。风格是什么并不重要,只要它有一些。 ;-)
第一个构造函数是constexpr 和explicit,这意味着如果输入是编译时常量,则构造的持续时间可以是编译时常量,并且输入不会隐式转换为持续时间。
此构造函数的总体目的是显式将标量(或标量的仿真)转换为chrono::duration。
模板参数列表中的第二个typename 是对_Rep2 的约束。它说:
_Rep2 必须隐式转换为rep(rep 是duration 的表示类型),并且
要么rep 是浮点类型(或模拟浮点类型),要么_Rep2 不是浮点类型(或模拟浮点类型)。
如果不满足这些约束,则此构造函数实际上不存在。这些约束的效果是您可以从浮点和整数参数构造基于浮点的durations,但基于整数的durations 必须从整数参数构造。
此约束的基本原理是防止静默丢弃浮点参数的小数部分。例如:
minutes m{1.5}; // compile-time error
这个不会编译,因为minutes 是基于整数的,并且参数是浮点数,如果它编译了,它会默默地丢弃.5 导致1min。
现在是第二个chrono::duration 构造函数:
template <typename _Rep2,
typename _Period2,
typename = typename enable_if
<
treat_as_floating_point<rep>::value ||
(ratio_divide<_Period2, period>::den == 1 &&
!treat_as_floating_point<_Rep2>::value)
>::type>
constexpr
duration(const duration<_Rep2, _Period2>& __d)
: __r(duration_cast<duration>(__d).count())
{ }
此构造函数用作 converting chrono::duration 构造函数。也就是说,它将一个单位转换为另一个单位(例如,hours 到 minutes)。
同样,模板参数Rep2 和Period2 有一个约束。如果不满足这些约束,则构造函数不存在。约束是:
rep 是浮点数,或者
_Period2 / period 产生分母为 1 的 ratio,_Rep2 是整数类型(或其仿真)。
此约束的效果是,如果您有浮点持续时间,那么 任何 其他持续时间(整数或基于浮点的)将隐式转换为它。
但是,基于整数的持续时间更加挑剔。如果您要转换为基于整数的持续时间,则源持续时间不能是基于浮点的并且从基于整数的源持续时间到目标的转换基于整数的持续时间必须准确。也就是说,转换不能除以除 1 之外的任何数字(只能相乘)。
例如:
hours h = 30min; // will not compile
minutes m = 1h; // ok
第一个示例无法编译,因为它需要除以 60,导致 h 不等于 30min。但是第二个示例可以编译,因为m 将完全等于1h(它将保持60min)。
你可以从中得到什么:
始终让<chrono> 为您进行转换。如果您在代码中乘以或除以 60 或 1000(或其他),则不必要地引入了错误的可能性。此外,如果您将所有转换委托给<chrono>,<chrono> 会通知您是否有任何有损转换。
-
尽可能使用隐式<chrono> 转换。它们要么编译并准确,要么不编译。如果它们不编译,则意味着您要求进行涉及截断错误的转换。可以要求截断错误,只要您不意外这样做。请求截断转换的语法是:
hours h = duration_cast<hours>(30min); // ok, h == 0h