
Substitution Failure Is Not An Error
SFINAE is a technique that is often used in C++ Template Programming.
It restrains function parameter types by using the mechanism of how the compiler deduces appropriate overloaded functions and calling the appropriate (overloaded)function you intend.
Before we begin talking about SFINAE, let's take a look at a similar situation.
#include <iostream>
void foo(double x){
std::cout << x << " is double!" << std::endl;
}
void foo(int x){
std::cout << x << " is int!" << std::endl;
}
int main(){
double a = 3.14;
int b = 1;
foo(a);
foo(b);
return 0;
}
The outputs are:
3.14 is double!
1 is int!
The result is very obvious.
The compiler deduces the overloaded function foo from its parameter a and b.
Explanation
What SFINAE is trying to do is the same as above, but there are some differences.
In the above example, what will happen if you remove the function that takes double as a parameter?
There can be a narrowing conversion(double-to-int) warning, but it compiles well.
But in SFINAE, if you pass other types to a function that is not what you intended, it will make syntax failure(and resulting in a compilation error if compiled).
In other words, if there's a two function and one makes syntax failure and the other doesn't, the compiler will guess that the non-syntax failing function is correct and call that one.
Like this, you intended Substitution Failure but it's to call the appropriate overloaded function.
So it is Not An Error(since it compiles well).
How odd the name is... can you guess how to pronounce it? :-s
Of course, SFINAE will fail in the below cases.
- All function are syntax failing(for the given type)
- More than 2 functions are non-syntax failing
Example
C++ 11
#include <iostream>
#include <type_traits>
template<typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
void foo(T x){
std::cout << x << " is floating point!" << std::endl;
}
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void foo(T x){
std::cout << x << " is integral!" << std::endl;
}
int main(){
double a;
int b;
foo(a);
foo(b);
return 0;
}
C++ 14
std::enable_if_t is added! 15 less words
#include <iostream>
template<typename T, std::enable_if_t<std::is_floating_point<T>::value, int> = 0>
void foo(T x){
std::cout << x << " is floating point!" << std::endl;
}
template<typename T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
void foo(T x){
std::cout << x << " is integral!" << std::endl;
}
int main(){
double a;
int b;
foo(a);
foo(b);
return 0;
}
In the above example, if we remove the first foo, then calling foo(a) is a syntax failure and it won't compile.
Like this, restricting types with std::enable_if to call appropriate overloaded function is called SFINAE.
You can do the same intend(deducing appropriate overloaded functions) with Tag Dispatching.
Questions, Feedbacks, and comments are very helpful to me!
'C++ > 템플릿(Template)' 카테고리의 다른 글
C++ 템플릿(Template): CRTP (2) | 2020.10.28 |
---|---|
C++ 템플릿(Template): 꼬리표 분배(Tag Dispatching) 기법 (0) | 2020.10.26 |