2

Stroustrup C++ 4th Ed Page 796 states that

"If Enable_if’s condition evaluates to false, the whole function declaration of which it is part is completely ignored." and "...we don’t declare anything.".

I have also read this suggested thread in which SFINAE only works if substitution in argument deduction of a template argument makes the construct ill-formed.

For this example, I am trying to understand how SFINAE omits the Enable_if<false, T> f0(int x) {}; construct.

Is it because of the lack of a return type ::type makes the template construct ill-formed language-wise?

#include <type_traits>
using namespace std;

template<bool B, typename T>
using Enable_if = typename std::enable_if<B, T>::type;

struct X 
{
   template <class T>
   Enable_if<false, T> f0(int x) {};
   template <class T>
   Enable_if<true, T> f0(int x) {};
};

int main(void)
{
   X xx;
   xx.f0<void>(0);
   return 0;
}

I understand the case in the prior mentioned thread for a construct:

template <typename enable_if<false>::type* = nullptr> 
void f0() {}

this is because the template parameter is ill-formed (no ::type to assign nullptr to.)

JeJo
  • 30,635
  • 6
  • 49
  • 88
notaorb
  • 1,944
  • 1
  • 8
  • 18
  • 1
    "Is it because of the lack of a return type ::type makes the template construct ill-formed language-wise? " <- Yes, and the fact that the compiler is allowed to try other functions in the overload set. – einpoklum Jul 26 '20 at 10:47

1 Answers1

2

I'm trying to understand how SFINAE omits the Enable_if<false, T> f0(int x) {}; construct. Is it because of the lack of a return type ::type makes the template construct ill-formed language-wise?

Short answer: NO!

You need to have a look, how SFNINAE basically works form a good c++ book. For instance from the cppreference.com

This rule applies during overload resolution of function templates: When substituting the explicitly specified or deduced type for the template parameter fails, the specialization is discarded from the overload set instead of causing a compile error.

Meaning, you need first of all overloaded template-functions! This has been achieved in the given example code.

Secondly, the part of std::enable_if. It checks the condition you provide in

template< bool B, class T = void >
//       ^^^^^^^ -----------------------> here!!
struct enable_if;

at compile-time and, decide whether to activate the part below or not.

The standard library component std::enable_if allows for creating a substitution failure in order to enable or disable particular overloads based on a condition evaluated at compile time.

In your code, for the given overload

template <class T>
Enable_if<false, T> f0(int x) {};
//        ^^^^^ ---------------> CONDITION == false

the condition is false, and hence in effect, this part (code) will not be there after the compiler done with the compilation.


Is it because of the lack of a return type ::type makes the template construct ill-formed language-wise?

For the reason mentioned above, NO; that is not the reason!

By providing a template-type-alias like this

template<bool B, typename T>
using Enable_if = typename std::enable_if<B,T>::type;
//                                            ^^^^^^^ --> type has been mentioned here!

you have mentioned the ::type via the alias type Enable_if</*condition*/, T>.

JeJo
  • 30,635
  • 6
  • 49
  • 88