I was writing a partial specialization for a class when the template parameter is derived from a specific type. My implementation is as follow -
struct base {};
struct derived: public base {};
template <typename T, typename=void>
struct foo {
foo() { std::cout << "Version 1" << std::endl; }
};
template <typename T>
struct foo <T, typename std::enable_if<std::is_base_of<base, T>::value>::type> {
foo() { std::cout << "Version 2" << std::endl; }
};
This works as expected - when I instantiate foo<int>, the constructor prints Version 1 and when I instantiate foo<derived>, the constructor prints Version 2.
Now, I was testing something and wanted to disable the partial specialization, so I just changed it to -
template <typename T>
struct foo <T, typename std::enable_if<false>::type> {
foo() { std::cout << "Version 2" << std::endl; }
};
I just replaced std::is_base_of<base, T>::value with the constant false. But this time the compiler started issuing warnings like std::enable_if<false, void> doesn't have type.
Why does it behave this way? Why does SFINAE not kick in here? Why does the parameter to std::enable_if HAVE to depend on the template parameter?
Why does SFINAE not kick in here?
SFINAE stands for "substitution failure is not an error". If your argument to std::enable_if is not dependent, then there is no substitution and so it makes sense that it wouldn't apply.
Specifically the standard says the program is ill-formed, no diagnostic required, if
a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, [...]
(from [temp.res.general]/8.4) of the post-C++20 draft N4868)
std::enable_if<false>::type is not dependent and ill-formed immediately following the definition of your template.
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