I am using function SFINAE heavily in a project and am not sure if there are any differences between the following two approaches (other than style):
#include <cstdlib> #include <type_traits> #include <iostream> template <class T, class = std::enable_if_t<std::is_same_v<T, int>>> void foo() { std::cout << "method 1" << std::endl; } template <class T, std::enable_if_t<std::is_same_v<T, double>>* = 0> void foo() { std::cout << "method 2" << std::endl; } int main() { foo<int>(); foo<double>(); std::cout << "Done..."; std::getchar(); return EXIT_SUCCESS; }
The program output is as expected:
method 1 method 2 Done...
I have seen method 2 used more often in stackoverflow, but I prefer method 1.
Are there any circumstances when these two approaches differ?
Substitution failure is not an error (SFINAE) refers to a situation in C++ where an invalid substitution of template parameters is not in itself an error. David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques.
So the simple answer is YES.
" typename " is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type.
I have seen method 2 used more often in stackoverflow, but I prefer method 1.
Suggestion: prefer method 2.
Both methods work with single functions. The problem arises when you have more than a function, with the same signature, and you want enable only one function of the set.
Suppose that you want enable foo()
, version 1, when bar<T>()
(pretend it's a constexpr
function) is true
, and foo()
, version 2, when bar<T>()
is false
.
With
template <typename T, typename = std::enable_if_t<true == bar<T>()>> void foo () // version 1 { } template <typename T, typename = std::enable_if_t<false == bar<T>()>> void foo () // version 2 { }
you get a compilation error because you have an ambiguity: two foo()
functions with the same signature (a default template parameter doesn't change the signature).
But the following solution
template <typename T, std::enable_if_t<true == bar<T>(), bool> = true> void foo () // version 1 { } template <typename T, std::enable_if_t<false == bar<T>(), bool> = true> void foo () // version 2 { }
works, because SFINAE modify the signature of the functions.
Unrelated observation: there is also a third method: enable/disable the return type (except for class/struct constructors, obviously)
template <typename T> std::enable_if_t<true == bar<T>()> foo () // version 1 { } template <typename T> std::enable_if_t<false == bar<T>()> foo () // version 2 { }
As method 2, method 3 is compatible with selection of alternative functions with same signature.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With