I have seen the word SFINAE mentioned in several questions, I don't know if it is all in capital letters or as a proper name: Sfinae.
Searching in Stack Overflow in Spanish I find that there are even standard documents that refer to this term, such as n3462 mentioned in How to know the version of the C standard that I am using in code? , but as much as I search I don't see that it is a library or a class. So I wonder:
To begin with, SFINAE is an acronym for:
It could be translated as FESNEUE or FASNEUE:
For the RAE an acronym is written in capital letters if it is necessary to spell it:
Since it can be read normally (even the English version) I (personally) would write it as if it were a normal word, so let's answer the question...
What is sfinae (fesneue/fasneue)?
This is a curious
template
feature of how C++ templates ( ) work. This feature tells us that failing to substitute a template parameter does not have to be an error .To understand this operation, we can see what happens with a simple template:
When we use the above template, the template goes through an instantiation process , one of the first steps is to substitute the generic parameters (
T
andU
in the example) with the provided (or inferred) parameters:Substitute.
In this instantiation of
plantilla
a function is created like this:The generic parameter
T
has been replaced withint
whileU
has been replaced withfloat
and will print123
to the console.Fail!.
If we change
plantilla
as follows:When making the previous call the resulting substitution will be:
Since the type
float
does not have a subtypevalue_type
, the substitution fails with an error.Do not fail!.
But if we had both functions:
When instantiating the template we would have a version that fails and another that does not:
In this case, the compiler instantiates all the templates and tries to substitute all the parameters, if after the substitution there is one (and only one) valid version of the template then it will not produce an error.
That is to say, in this case we have been able to see that a F allo w to Substitute Is N o t an E rror .
Okay, I understood but... what is it for?
The fasneue behavior is in the nature of C++ templates. Templates were designed this way to solve other problems (such as causing unexpected errors when including templates from third-party libraries) but some C++ programmers saw additional potential in this behavior, as it allows rudimentary compile-time type introspection.
For example, if we have a function that we want to act differently depending on whether it is called with integers or floating point numbers:
Calling it with a type other than
int
ofloat
would fail due to ambiguity:A possible solution would be to create overloads for all types:
It is a hassle to create 14 functions almost all the same with repeated code, but with fesneue we can separate these functions into integer and float:
The two previous template functions allow us to discern if the received type is an integer or floating point value with only two versions of the function, using other templates to achieve this:
type characteristics
<type_traits>
.This library offers templates that allow types to be interrogated to find out if they meet certain characteristics, apart from the " Is the type integer? " and " Is the type floating point? " that we have already seen, it can be used to check whether the type is a pointer, a class, or a function. All of these called templates
is_xxxx
result in a boolean value (computed at compile time) with a value of true if the check passes.Conditional fesneue
<std::enable_if>
The template
std::enable_if
is an object that, if the condition received as the first parameter is met, will contain the type provided as the second template parameter; otherwise it will be an empty object.Knowing this, the last example would work as follows:
In the substitution phase, using the unsigned integer literal the following would happen:
std::is_integral_v<unsigned int>
is replaced bytrue
.std::enable_if_t<unsigned int, true>
is replaced byunsigned int
.f
remains asf(unsigned int)
.std::is_floating_point_v<double>
is replaced byfalse
.std::enable_if_t<double, false>
is replaced by nothing.In the second case, the substitution that fails is the first one and the second version of the function
f
that has not failed the substitution is chosen.