Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Approaches to function SFINAE in C++

Tags:

c++

sfinae

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?

like image 981
keith Avatar asked Dec 24 '19 21:12

keith


People also ask

What is Sfinae used for?

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.

Will concepts replace Sfinae?

So the simple answer is YES.

What is Typename C++?

" 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.


1 Answers

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.

like image 152
max66 Avatar answered Oct 03 '22 03:10

max66