Consider the following function:

int negate(int i) { // (1)  
    return -i;

and the following function template:

template<class F>  
typename F::result_type negate(F const& f) { // (2)  
    return -f();

where F is some function object type (so that a member type F::result_type exists). Let us now consider the following invocation:


The first definition is obviously a better match. Nevertheless, in order to find this out, the compiler must consider (and instantiate the prototypes) of both definitions.

Instantiating the latter definition with F as int results in:

int::result_type negate(int const& f);  

which return type is invalid. Treating this situation as a compilation error would mean preventing the programmer from adding unrelated function templates. Thanks to SFINAE this is not the case.

If an invalid argument or return type is formed during the instantiation of a function template, the instantiation is simply removed from the overload resolution set, instead of causing a compilatior error.

std::enable_if is a metafunction that leverages SFINAE to conditionally remove functions from the overload resolution set.

template<bool B, class T = void>  
struct enable_if {};

template<class T>  
struct enable_if<true, T> {  
    using type = T; 

Similarly to int::result_type, std::enable_if<B, T>::type is either a valid or invalid type expression depending on the value of B.

Almost verbatim from: