ExBen
ExBen

Reputation: 185

template parameter with default value for class

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

Answers (1)

max66
max66

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

Related Questions