Search code examples
c++templatesintc++-chrono

Different results between an integer variable and casting an integer to an integer


I've written a generic timer class that uses the std::chrono time for the timer. This is a code example that shows the issue:

#include <iostream>
#include <chrono>

template <typename Rep, typename TimeType>
class Timer {
  public:
    Timer(const std::chrono::duration<Rep, TimeType> timerLength);
    ~Timer() = default;
  private:
    std::chrono::duration<Rep, TimeType> _timerLength;
};

template <typename Rep, typename TimeType>
Timer<Rep, TimeType>::Timer(const std::chrono::duration<Rep, TimeType> timerLength) : _timerLength{timerLength} {}

int main()
{
    constexpr int time_ms = 1000;

    Timer timer(std::chrono::milliseconds(time_ms));

    return 0;
}

This code results in the error: error: deduced class type ‘Timer’ in function return type.

This error can be removed by placing an actual int directly in the timer in main:

Timer timer(std::chrono::milliseconds(1000));

Additionally, this error can be removed by casting the time_ms parameter to an integer:

Timer timer(std::chrono::milliseconds(`static_cast<int>(time_ms)));

I expected the same result of an integer variable and casting an integer to an integer.

This error cannot be removed by removing the constexpr of the time_ms variable.

My question is: What are the differences between an integer variable and casting an integer to an integer (as well as inserting the number directly in the std::chrono::milliseconds())? And why does it make a difference in the first place?


Solution

  • You are a victim of a vexing parse. With -Wall clang will even warn about that

    source>:24:16: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
    
        Timer timer(std::chrono::milliseconds(time_ms));
    
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    

    and suggests a fix as well.

    <source>:24:17: note: add a pair of parentheses to declare a variable
    
        Timer timer(std::chrono::milliseconds(time_ms));
    
                    ^
    
                    (                                 )
    

    But you can disambiguate in other ways as well.

    Timer timer{std::chrono::milliseconds(time_ms)};
    Timer timer(std::chrono::milliseconds{time_ms});
    auto timer = Timer(std::chrono::milliseconds(time_ms));
    Timer timer(static_cast<std::chrono::milliseconds>(time_ms));
    

    as well as putting an int literal in the expression, or explicitly casting to an int, as you noticed yourself.