Home > Net >  How to declare a template function with a std::ratio template parameter
How to declare a template function with a std::ratio template parameter

Time:11-22

I'm trying to define three functions with C 14 as below:

template <typename D = std::chrono::seconds>
typename D::rep test() {
    // somethinig
}

template <std::intmax_t N, std::intmax_t D = 1, typename V = uint64_t>
V test() {
     // something
}

The two functions work as expected. I can call them like test<std::chrono::minutes>() and test<60>. Now, I want to define the third function, which accepts a std::ratio as a template parameter.

template <template<std::intmax_t, std::intmax_t> class R, std::intmax_t N, std::intmax_t D, typename V = uint64_t>
V test() {
    // R<N, D> should be std::ratio<N, D>
    // something
}

But in this case I would get a compile-time error while calling test<std::milli>(). I think it's because the compiler mixed up the first function and the third function. How could I define the third one?

CodePudding user response:

Define some traits to detect whether the type T is a specialization of duration or ratio:

#include <chrono>
#include <ratio>

template<class>
struct is_duration : std::false_type { };

template<class Rep, class Period>
struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type { };

template<class>
struct is_ratio : std::false_type { };

template<std::intmax_t Num, std::intmax_t Denom>
struct is_ratio<std::ratio<Num, Denom>> : std::true_type { };

Then use enable_if to enable the corresponding function according to the type of T:

template<typename D = std::chrono::seconds, 
  std::enable_if_t<is_duration<D>::value>* = nullptr>
typename D::rep test() {
  // somethinig
}

template<typename R, typename V = uint64_t,
  std::enable_if_t<is_ratio<R>::value>* = nullptr> 
V test() {
  // R<N, D> should be std::ratio<N, D>
  // something
}

Demo.

CodePudding user response:

Another option is tag dispatching:

template <typename> struct tag{};

template <typename Rep, typename Period> 
Rep test(tag<std::chrono::duration<Rep, Period>>)
{
    // ...
}

template <std::intmax_t Num, std::intmax_t Denom> 
uint64_t test(tag<std::chrono::ratio<Num, Denom>>)
{
    // ...
}

template <typename T> 
auto test() -> decltype(test(tag<T>{}))
{
    return test(tag<T>{});
}

template <std::intmax_t N, std::intmax_t D = 1, typename V = uint64_t>
V test() {
    // ...
}
  • Related