Patrick le Duc
Patrick le Duc

Reputation: 113

std::chrono::duration integer difficulties

I have this simple template stopwatch timer which I'm planning to use in my next project, whenever I instantiate this class using "Timer< float >" everything works fine, however if I use "Timer< int >" I get errors.

timer.h(18): error C2440: '' : cannot convert from 'std::chrono::duration<_Rep,_Period>' to 'std::chrono::duration<_Rep,_Period>'

I am clueless why this happens, all help appreciated, thanks in advance!

template< typename type > class Timer
{

public:

    void Start(){ m_Start = m_Time.now(); }
    void Reset(){ m_Start = m_Time.now(); m_Split = m_Start; }
    void Split(){ m_Split = m_Time.now(); }

    type HoursSinceStart()          { return std::chrono::duration< type, std::ratio< 3600 > >( m_Time.now() - m_Start ).count(); }
    type MinutesSinceStart()        { return std::chrono::duration< type, std::ratio< 60 > >( m_Time.now() - m_Start ).count(); }
    type SecondsSinceStart()        { return std::chrono::duration< type, std::ratio< 1 > >( m_Time.now() - m_Start ).count(); }
    type MilliSecondsSinceStart()   { return std::chrono::duration< type, std::milli >( m_Time.now() - m_Start ).count(); }
    type MicroSecondsSinceStart()   { return std::chrono::duration< type, std::micro >( m_Time.now() - m_Start ).count(); }
    type NanoSecondsSinceStart()    { return std::chrono::duration< type, std::nano >( m_Time.now() - m_Start ).count(); }

    type HoursSinceSplit()          { return std::chrono::duration< type, std::ratio< 3600 > >( m_Time.now() - m_Split ).count(); }
    type MinutesSinceSplit()        { return std::chrono::duration< type, std::ratio< 60 > >( m_Time.now() - m_Split ).count(); }
    type SecondsSinceSplit()        { return std::chrono::duration< type, std::ratio< 1 > >( m_Time.now() - m_Split ).count(); }
    type MilliSecondsSinceSplit()   { return std::chrono::duration< type, std::milli >( m_Time.now() - m_Split ).count(); }
    type MicroSecondsSinceSplit()   { return std::chrono::duration< type, std::micro >( m_Time.now() - m_Split ).count(); }
    type NanoSecondsSinceSplit()    { return std::chrono::duration< type, std::nano >( m_Time.now() - m_Split ).count(); }

private:

    std::chrono::high_resolution_clock m_Time;

    std::chrono::high_resolution_clock::time_point m_Start;
    std::chrono::high_resolution_clock::time_point m_Split;
};

Upvotes: 1

Views: 2635

Answers (1)

Howard Hinnant
Howard Hinnant

Reputation: 218700

The chrono library is trying to save you from accidentally loosing information during a units conversion. For example, it is always ok to convert minutes to nanoseconds, because nanoseconds can always exactly represent any number of minutes.

But nanoseconds won't so easily convert to minutes because this conversion is "lossy". The conversion won't be exact, it will have truncation (roundoff) error. If you really want such a conversion, you have to be explicit about it. This is what std::chrono::duration_cast is for. For example:

minutes m = duration_cast<minutes>(ns);

This says to convert nanoseconds to minutes, and truncate towards zero when you have some left over nanoseconds.

This "safety net" is only applicable to integral representations (e.g. int). When you use floating-point based durations, an implicit conversion from nanoseconds to minutes is allowed because the floating point type will represent fractions of a minute coming from left over nanoseconds.

In case you need rounding modes other than "truncate towards zero", here are some utilities to do so.

Upvotes: 4

Related Questions