When using SFINAE to select constructor overloads in the past, I have typically used the following:
template <typename T>
class Class {
public:
template <typename U = T, typename std::enable_if<std::is_void<U>::value, int>::type=0>
Class() {
std::cout << "void" << std::endl;
}
template <typename U = T, typename std::enable_if<!std::is_void<U>::value, int>::type=0>
Class() {
std::cout << "not void" << std::endl;
}
};
However, I just came across this alternative:
template <typename U = T, typename std::enable_if<std::is_void<U>::value>::type...>
Class() {
std::cout << "void" << std::endl;
}
Considering that the following is illegal ...
template <typename U = T, void...> // ERROR!
Class() { }
... how does the alternative above using ellipses rather than a non-type template argument work?
Full code: http://coliru.stacked-crooked.com/a/64a1aaf13ce6099b
My previous answer was wrong. Sorry. I'm just going to fix it.
This declaration:
template <typename U = T, void...>
Class() { }
violates [temp.res]/8:
The program is ill-formed, no diagnostic required, if [...] every valid specialization of a variadic template requires an empty template parameter pack
It's no diagnostic required, but the compiler chooses to issue one anyway. Either way, the code is ill-formed.
On the other hand
template <typename U = T, std::enable_if_t<std::is_void<U>::value>...>
Class() { }
doesn't violate this requirement. We have an empty pack, so we don't run afoul of the fact that you can't use void
as a non-type template parameter. Additionally, a hypothetical specialization of enable_if
could provide a type that isn't void
there so it's not ill-formed due to the above limitation.
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