【问题标题】:What is the best way to form custom std::chrono::durations and std::ratios?形成自定义 std::chrono::durations 和 std::ratio 的最佳方法是什么?
【发布时间】:2015-03-08 22:40:12
【问题描述】:

我正在阅读this excellent answer,它使用可笑的持续时间单位microfortnights 以令人难忘的方式说明了一个好点。

typedef std::ratio<756, 625> microfortnights;
std::chrono::duration<int, microfortnights> two_weeks(1000000);

我想到了这个问题:

如果我真的想这样做(更有可能是其他一些重要的 持续时间,例如在一帧期间或 N 个周期期间可用的时间 处理器),最好的方法是什么?

我知道ratio&lt;N, D&gt; 将创建一个与ND 的每个值相关联的唯一类型。所以ratio&lt;4, 6&gt;ratio&lt;2, 3&gt; 是不同的类型,即使它们代表相同的(减少的)分数。我是否总是需要进行数学运算才能将转换因子简化为简化项?

这样写会更方便:

using microfortnights = std::chrono::duration<long, ratio<86400*14, 1000000>>;

代替:

using microfortnights = std::chrono::duration<long, ratio<756, 625>>;

但是这些将是两种不同的类型,而不是相同的类型。第一个表达式更容易检查正确性。但是这个分数有很多表示,第二个可以说是规范的,因此是首选的。如果我的程序中有太多实际上代表同一个单元的类型,那么这可能会导致不必要的模板代码膨胀。

【问题讨论】:

  • 可以将问题标题改写为std::ratio吗?除了所选示例之外,总体主题似乎与 chrono 几乎没有关系?
  • 你说得很好。但是我想继续关注durations,否则我担心我的观众不会看到ratio 的实际应用。我在标题中添加了ratio,以便搜索ratio 将更容易找到此Q/A。
  • 呵呵。无论如何+1。 (具有讽刺意味的是,我花了一段时间才发现这实际上比仅仅创建难以捉摸的 microfortnight “正确” :))
  • 不是2000000 microfortnights four_weeks,不是two_weeks

标签: c++ c++11 chrono


【解决方案1】:

为了简洁起见,下面我将忽略命名空间。 duration 在命名空间 std::chrono 中,ratio 在命名空间 std 中。

有两种很好的方法可以始终确保您的 ratio 减少到最低项,而无需自己进行算术运算。第一个很直接:

直接公式

如果您只想直接跳转到microfortnights,但不必弄清楚 86,400*14/1,000,000 的缩减分数是 756/625,只需在::type 之后添加ratio

using microfortnights = duration<long, ratio<86400*14, 1000000>::type>;

每个ratio&lt;N, D&gt; 的嵌套type 是另一个ratio&lt;Nr, Dr&gt;,其中Nr/Dr 是减少的分数N/D。如果N/D 已经减少,那么ratio&lt;N, D&gt;::typeratio&lt;N, D&gt; 的类型相同。事实上,如果我已经发现 756/625 是正确的缩减分数,但只是偏执地认为它可能会进一步缩减,我本可以这样写:

using microfortnights = duration<long, ratio<756, 625>::type>;

因此,如果您对您的ratio 是否以最低术语表示有任何疑问,或者只是不想被检查所困扰,您可以随时将::type 附加到您的ratio 类型以确保.

冗长的表述

自定义持续时间单位通常会作为系列的一部分出现。让整个家庭都可以使用您的代码通常很方便。例如microfortnights 显然与fortnights 相关,而weeks 又与weeks 相关,days 派生自hours(或seconds,如果您愿意)。

通过一次建立一个家庭,您不仅可以让整个家庭都可以使用,还可以通过尽可能简单的转换将一个家庭成员与另一个家庭成员联系起来,从而减少出错的机会。此外,使用std::ratio_multiplystd::ratio_divide,而不是乘以文字也意味着您不必在任何地方都插入::type,以确保您将ratio 保持在最低限度。

例如:

using days = duration<long, ratio_multiply<hours::period, ratio<24>>>;

ratio_multiply 是乘法结果的typedef-name已经减少到最低限度。所以上面是完全相同的类型 em> 为:

using days = duration<long, ratio<86400>>;

您甚至可以在同一个翻译单元中同时拥有两个定义,并且不会出现重新定义错误。无论如何,您现在可以说:

using weeks           = duration<long, ratio_multiply<days::period,       ratio<7>>>;
using fortnights      = duration<long, ratio_multiply<weeks::period,      ratio<2>>>;
using microfortnights = duration<long, ratio_multiply<fortnights::period, micro>>;

我们最终得到了microfortnightstypedef-name,它与我们直接制定的完全相同的类型,但是通过一系列更简单的转换。我们仍然不必为将分数简化为最低项而烦恼,而且我们现在有几个有用的单位,而不仅仅是一个。

还要注意使用std::micro 代替std::ratio&lt;1, 1000000&gt;。这是另一个避免粗心错误的地方。很容易(至少对我而言)错误输入(和误读)零的数量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-18
    • 2016-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-03
    • 1970-01-01
    相关资源
    最近更新 更多