With the following template and specialization:
template<typename T, typename = void>
struct A {
void operator()() {
std::cout << "primary" << std::endl;
}
};
template<typename T>
struct A<T, decltype(T().f())> {
void operator()() {
std::cout << "specialization" << std::endl;
}
};
used like this:
struct X {
bool f() { return false; }
};
int main()
{
A<X>()();
return 0;
}
the primary template is resolved, when one would expect partial specialisation to be selected. However, when changed to:
template<typename T>
struct A<T, typename std::enable_if<std::is_object<decltype(T().f())>::value>::type> {
void operator()() {
std::cout << "specialization" << std::endl;
}
};
the specialization is chosen. Why isn't specialization chosen in the original example?
You have instantiated:
A<X>
Which leverages a default template parameter to become:
A<X,void>
Your specialization, however, is:
template<typename T>
struct A<T, decltype(T().f())>
Which, for template parameter X becomes:
struct A<X, decltype(X().f())>
Which is:
struct A<X, bool>
So, your specialization is not the correct choice, because A<X,bool> does not specialize A<X,void>.
If you want your specialization to work for all well-formed instances of T().f(), you can use C++17's std::void_t
std::void_t will evaluate to void for any well-formed template parameters passed to it.
template<typename T>
struct A<T, std::void_t<decltype(T().f())>> {
void operator()() {
std::cout << "specialization" << std::endl;
}
};
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