Reputation: 341
I saw code like the following:
using EnableIfIntegral = typename std::enable_if<
std::is_integral<T>::value || std::is_enum<T>::value, int>::type;
template <typename T, EnableIfIntegral<T> = 0>
constexpr int Seconds(T n) {
return time_internal::FromInt64(n, std::ratio<1>{});
}
template <std::intmax_t N>
constexpr int FromInt64(int64_t v, std::ratio<1, N>) {
// Do Something
}
I understand what a template function is. Why in the template parameter list, does it have SomeClass<T> = 0
? I know T
is the template parameter.
Why is std::ratio<1, N>
a parameter?
Upvotes: 4
Views: 732
Reputation: 118445
I'll answer the first of your two questions.
using EnableIfIntegral = typename std::enable_if<
std::is_integral<T>::value || std::is_enum<T>::value, int>::type;
I'm fairly certain that you accidentally left out the previous line, which should be
template<typename T>
So the full declaration is
template<typename T>
using EnableIfIntegral = typename std::enable_if<
std::is_integral<T>::value || std::is_enum<T>::value, int>::type;
This is pretty big pill to swallow, and I'll come back and discuss the finer details of this declaration in a moment, but what happens here is that if the stars and the moons are alined just right, this becomes:
template<typename T>
using EnableIfIntegral = int;
In other words, a template type that's just a simple alias for an garden variety int
. Nothing more than that. Moving onto to the next declaration:
template <typename T, EnableIfIntegral<T> = 0>
constexpr int Seconds(T n) {
This simply becomes
template <typename T, int = 0>
constexpr int Seconds(T n) {
In other words, a simple template parameter, an int
constant that defaults to 0.
That's it, and nothing more. This does absolutely nothing, and that's precisely the intended result here.
The first template parameter, T
gets deduced from the actual parameter to the Seconds()
template function. Then the 2nd template parameter passes the T
template type to the EnableIfIntegral
template alias declaration, which, hopefully, if all the stars and the moons are properly aligned, does nothing.
Now, when do the stars and the moons properly align? It's when the deduced template type is either some integral type or some enum
type. Then everything just works.
But if you do something silly, like:
std::string what_is_this;
Seconds(what_is_this);
A very loose description of what will happen: the first template parameter to Seconds
gets deduced as std::string
. So far so good, but we're already doomed because what's inside the Seconds
template function will not be able to handle a std::string
value. Normally this will typically result in a typical, indecipherable (to mere mortals) C++ compiler error message.
But things are not going to get this far. What happens first is that the deduced T
template parameter, which is now std::string
, gets forwarded to EnableIfIntegral
, and this template alias will fail to resolve. For all the gory details why, look up what std::enable_if
does in your favorite C++ book. The exact details of how that happens is not very important, the point is that the template substitution for the Seconds()
template itself will fail. The compiler will not find a suitable Seconds
template that will match this function call.
This situation typically produces a much simpler error message from your compiler. Your compiler's error message will be much basic, something along the lines "Hey, what's this Seconds template being called here? I know nothing about it". You will look at the code and realize "Silly me, I'm passing a std::string
but I need to pass an integral value instead". Oops.
Overall, what this is, is just a common approach to make the pain of using a C++ library less painful, when things go wrong and don't compile. Without this trick, the compiler will whine about the time_internal::FromInt64
function call (based on the shown code in the question), but there's nothing wrong with that function call. The problem is really with whatever calls Seconds
, that's where the problem is, and this common approach helps the compiler produce a better error message.
Upvotes: 6