Reputation: 185
I dont quite understand below code, there are two parameters for the template, the second one has class = xxxx
, This seems strange to me. Can you explain it to me how should I understand it? and besides std::enable_if
, is there any other use case for this c++ feature?
template < class T,
class = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even (T i) {return !bool(i%2);}
Upvotes: 2
Views: 2148
Reputation: 66240
One word: SFINAE.
Substitution Failure Is Not An Error.
Look for that word with google and a whole new world will open up for you.
Let see the meaning of your code.
std::is_integral<typename T>::value
It's a boolean value, dependant from type T
, with value true
if T
is a integral type, false
otherwise.
std::enable_if<bool B, typename T = void>::type
It's the type T
, when B == true
, nothing otherwise.
So, in your code
template < class T,
class = typename std::enable_if<std::is_integral<T>::value>::type>
when T
is a integral type, the second (unnamed) template argument is substituted with a type (the default: void
; but, in this case, the exact type is irrelevant) and the function is activated. On the contrary, when T
isn't a integral type, there is the failure in the substitution of the second template argument and this version of the is_even()
function isn't activated (for type T
) and, this is the important point, it isn't an error (another version of is_even()
can be activated).
More interesting can be see how to implement an alternative version of is_even()
, for non integral types. You can think that you can implement another version that negate std::is_integral
template < class T,
class = typename std::enable_if<false == std::is_integral<T>::value>::type>
but this don't work (is an error and don't compile) because you have two is_even()
templated function that differs (from the templates arguments point of view) only for a default argument.
A solution can apply SFINAE to the return value
#include <type_traits>
#include <iostream>
template <typename T>
typename std::enable_if<true == std::is_integral<T>::value, bool>::type
is_even (T const & i)
{ return ! (i%2); }
template <typename T>
typename std::enable_if<false == std::is_integral<T>::value, bool>::type
is_even (T const &)
{ return false; }
int main()
{
std::cout << "-- is 7 even ? " << is_even(7) << '\n';
std::cout << "-- is 8UL even ? " << is_even(8LL) << '\n';
std::cout << "-- is \"abc\" even ? " << is_even("abc") << '\n';
return 0;
}
In this way you have a version of is_even()
enabled for integral type and a second version (that return even false
) for non integral types.
p.s.: sorry for my bad english.
Upvotes: 4