#include <type_traits>
template<bool b>
struct S
{
template<typename = std::enable_if_t<b>>
S() {}
template<typename = std::enable_if_t<!b>>
S(int) {}
};
S<true> s{}; // error in clang/gcc, OK in VC2017
S<false> s{0}; // error in clang/gcc, OK in VC2017
In both cases clang/gcc try to instantiate the ctor that should actually be discarded due to SFINAE. The error message is:
error : no type named 'type' in 'std::enable_if< false, void>'; 'enable_if' cannot be used to disable this declaration
clang/gcc's instantiation of the other ctor is incorrect since it should not be on the list of possible overloads, right?
But before I file a bug I would like to read what others think. Maybe I don't get it right...
This is a bug in MSVC; clang and gcc are right.
The problem is that SFINAE happens during overload resolution only, not before. What I mean is, if the function is ill-formed even before you call it, it's an error.
When you use S<true>
for example, the whole class is instantiated. It will look a bit like this:
struct S_true
{
template<typename = void>
S() {}
template<typename = /*fail*/>
S(int) {}
};
As you can see, the second constructor is completely ill-formed, it's not a valid definition, because there is no type type
found (because of std::enable_if
). So SFINAE cannot even kick in, the class definition is ill-formed and diagnosed.
You need to make the template parameter b
part of the template parameter list of both constructors (have a look at @bolov's answer).
@Rakete1111 is 100% right.
You need to make the template parameter bool b part of the template parameter list of both constructors.
Here is how to do this (it's a pretty standard technique):
template<bool b>
struct S
{
template<bool bb = b, typename = std::enable_if_t<bb>>
S() {}
template<bool bb = b, typename = std::enable_if_t<!bb>>
S(int) {}
};
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