c++ SFINAE doesn't work in recursive function

SFINAE, which stands for Substitution Failure Is Not An Error, is a concept in C++ that allows the compiler to discard certain template functions from consideration during overload resolution. This is done when the substitution of template arguments fails, which means the function template cannot be instantiated with the given arguments. SFINAE is a powerful technique that enables template metaprogramming and can be used to write more flexible and generic code.

However, SFINAE doesn't work in recursive functions in C++. This is because the failure of substitution in a recursive function is not considered a failure in the context of the entire function template. In other words, if a substitution failure occurs in a recursive step of the function template, it doesn't cause the compiler to discard that specific overload from consideration.

To understand why SFINAE doesn't work in recursive functions, let's consider an example:

template <typename T>
void foo(T t) {
  foo(t - 1);
}

In this example, the function template foo takes a parameter of type T and recursively calls itself with the value t - 1. Now, let's assume we want to specialize this function template for int types, but we want to exclude float types. We can use SFINAE to achieve this:

template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
foo(T t) {
  foo(t - 1);
}

template <typename T>
typename std::enable_if<!std::is_integral<T>::value>::type
foo(T t) {
  // Do something else for non-integral types
}

In this example, we use std::enable_if and std::is_integral to enable the first overload of foo only for integral types. The second overload is used for non-integral types.

However, when we try to compile this code, we will encounter a compilation error. This is because the recursive step foo(t - 1) in the first overload of foo will always be instantiated, even for non-integral types. This leads to an infinite recursion and a compilation error.

To summarize, SFINAE doesn't work in recursive functions because the failure of substitution in a recursive step doesn't cause the compiler to discard that specific overload from consideration. The recursive step will always be instantiated, even if it leads to a substitution failure. This limitation of SFINAE in recursive functions is an important aspect to consider when writing template metaprogramming code in C++.