8

鉴于它std::chrono::duration可以表示两次之间的有符号差异,因此需要这种持续时间的绝对值似乎是一种非常常见的情况。例如,以下代码diff: -5按预期输出:

using namespace std;
using namespace std::chrono;

auto now = system_clock::now();
auto then = now - seconds(5);
auto diff = then - now;

cout << "diff: " << duration_cast<seconds>(diff).count() << endl;

能够做类似的事情会很好:

auto diff = abs(then - now);

但是,我看不到标准std::abschrono模板的任何特化,也看不到std::chrono::duration.

我应该如何将 astd::chrono::duration转换为它的绝对值?

4

1 回答 1

15

我会这样做:

template <class Rep, class Period>
std::chrono::duration<Rep, Period>
abs(std::chrono::duration<Rep, Period> d)
{
    Rep x = d.count(); 
    return std::chrono::duration<Rep, Period>(x >= 0 ? x : -x);
}

有关我希望是标准的其他实用程序,请参阅我的<chrono>实用程序列表。<chrono>请随意使用它们,将它们推荐给您的标准机构代表,或自己提出。

更新

当我写上面的内容时,我已经离开了我的游戏。我不会删除它,因为它为我自己和其他人提供了关于如何编写chrono实用程序的一个很好的教训。

我不喜欢它的地方:

  1. 它通过直接操作Rep.

  2. 它假定文字 0 可以隐式转换为,或至少与 . 相当Rep

  3. 没有理由不这样做constexpr

  4. 我对 unsigned 的行为不满意Rep。如果有人说:

    自动 d = abs(t1 - t0);

并且基于无符号持续时间,那么这可能是代码中的逻辑错误t1t0如果t1 < t0,那么您可能会得到一个不正确的、非常大的持续时间。如果那是您真正想要的,那么您不应该使用abs,而只需编写更简单的代码:

   auto d = t1 - t0;

为了解决这些问题,我abs将持续时间改写为:

template <class Rep, class Period,
          class = typename std::enable_if
          <
              std::chrono::duration<Rep, Period>::min() <
              std::chrono::duration<Rep, Period>::zero()
          >::type
         >
constexpr
inline
std::chrono::duration<Rep, Period>
abs(std::chrono::duration<Rep, Period> d)
{
    return d >= d.zero() ? d : -d;
}
  1. duration有 unary -,只需使用它。

  2. duration具有可自定义的zero特征,因此不必假设与0from密切合作Rep。就用它吧。

  3. 使用的所有操作都constexprabsconstexpr

  4. 静态函数minzeroconstexpr。使用这些来确定是否Rep已签名比使用诸如!std::is_unsigned. 即Rep可能是 aBigNum或 C11 timespec(增加了重载的算术运算符)。所以“已签名”的问题是用 来回答的min() < zero()。而现在这个版本abs将不接受一个duration<unsigned, milli>(例如)。

于 2014-01-24T01:20:24.903 回答