2

I have a class template Bird with a Boolean template parameter can_fly. Depending on that value, I want to enable a member function with the signature void fly();.

This is my code:

#include <type_traits>

template<bool can_fly>
class Bird {
public:
    template<typename void_t = typename std::enable_if<can_fly>::type>
    void_t fly() { /* ... */ }
};

int main() {
    Bird<true> flyingBird;
    flyingBird.fly();
    Bird<false> flightlessBird;

    return 0;
}

This code compiles fine in Visual Studio 2015, but GCC complains that there is "no type named 'type' in 'struct std::enable_if'" in the third line of main.

I thought the fact that there is no ::type in the false case was the entire point of SFINAE. Can somebody explain to me what I did wrong and what the correct approach is?

Daniel Wolf
  • 12,855
  • 13
  • 54
  • 80

1 Answers1

1

As mentioned in this answer:

enable_if works because the substitution of a template argument resulted in an error, and so that substitution is dropped from the overload resolution set and only other viable overloads are considered by the compiler.

In your case there is no substitution because can_fly is known at the moment of instantiation. You can create a dummy default bool template parameter to make SFINAE work properly:

template<bool can_fly>
class Bird {
public:
    template<bool X = can_fly, typename = typename std::enable_if<X>::type>
    void fly() { /* ... */ }
};

wandbox example

Community
  • 1
  • 1
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • 1
    Now I get it! In my code, the entire expression `std::enable_if::type` can be evaluated prior to overload resolution and results in an error. Whereas in your code, the expression `std::enable_if::type` can only be evaluated once `X` is known. Thanks a lot! – Daniel Wolf Dec 11 '16 at 22:08
  • 1
    upvoted, but in production code, you also want an `X == can_fly` inside the `enable_if`. This prohibits calling `Bird::fly();`.. Also you can use `...` and `_t` to avoid the `typename` and shorten the notation a bit like `template...> void fly() {}`. – TemplateRex Dec 20 '16 at 14:43