The absolute value of the std :: chrono :: duration object

Given that std::chrono::duration can represent the signed difference between the two times, it would seem that a very common case requires an absolute value of such a duration. For example, the following code outputs diff: -5 , as expected:

 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; 

It would be nice to do something like:

 auto diff = abs(then - now); 

However, I do not see any specialization of std::abs for chrono templates in the standard, and I cannot see any suitable member function in std::chrono::duration .

How do I convert std::chrono::duration to this absolute value?

+7
c ++ c ++ 11 chrono
source share
1 answer

I would do it like this:

 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); } 

See my list of <chrono> Utilities for the other <chrono> utilities that I desire were standard. Please feel free to use them, recommend them to your standards or suggest them yourself.

Update

I was offside when I wrote above. I do not delete it, as it serves as a good lesson for me and others on how not to write chrono utilities.

Things I don't like:

  • It unnecessarily reduces type safety by directly manipulating Rep .

  • The letter 0 is supposed to be implicitly converted, or at least compared to Rep .

  • There is no reason for this not to be constexpr .

  • I am not happy with the behavior for unsigned Rep . If you say:

    auto d = abs (t1 - t0);

and t1 and t0 are based on unsigned lengths, then this is most likely a logical error in the code. If t1 < t0 , then you are likely to get the wrong, very long duration. If this is what you really want, then you shouldn't use abs , but instead, just coding is easier:

  auto d = t1 - t0; 

To solve these problems, I rewrote abs for the duration as:

 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; } 
  • duration is unary - just use it.

  • duration has a custom zero sign, so you don't have to assume close collaboration with 0 from Rep . Just use it.

  • All used constexpr operations are labeled abs constexpr .

  • The static functions min and zero are equal to constexpr . Using these parameters to determine if a Rep is signed is more general than using a tag such as !std::is_unsigned . That is, Rep can be BigNum , or C11 timespec (supplemented by overloaded arithmetic operators). Therefore, the question "signed" is answered by min() < zero() . And now this version of abs will not accept duration<unsigned, milli> (for example).

+13
source share

All Articles