Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

enable_if for class template specialization with argument other than void

I know that a C++ compiler picks a template specialization in preference to the primary template:

template<class T, class Enable = void>
class A {}; // primary template

template<class T>
class A<T, std::enable_if_t<std::is_floating_point_v<T>, void>> {
}; // specialization for floating point types

However, I don't understand why the selection fails when a type other than void is used as argument to enable_if:

template<class T>
class A<T, std::enable_if_t<std::is_floating_point_v<T>, int>> {
}; // specialization for floating point types

The compiler would surely "see" class A<T, int>. So it certainly can't be SFINAE, nevertheless the primary template is preferred to the specialization.

This question arises from a context where a custom type detection machinery could be used instead of enable_if, e.g. an SFINAE friendly type extractor like common_type.

like image 239
klaus triendl Avatar asked Oct 16 '25 00:10

klaus triendl


2 Answers

When you have

A<some_floating_point_type> some_name;

The template parameters are some_floating_point_type and the implicit void. When the compiler instantiates

template<class T>
class A<T, std::enable_if_t<std::is_floating_point_v<T>, int>> {
}; // specialization for floating point types

it would get A<some_floating_point_type, int>, which does not match the A<some_floating_point_type, void> type that some_name has. Because of that, the specialization is ignored and you get the primary template. You can verify this by trying to create a A<some_floating_point_type, int> and you'll get that the specialization was picked.

I find it helpful to think of a specialization as an alternate recipe. First the template arguments are deduced, and then if they match any of the specializations, then we switch to using that alternate recipe. If not, then the original recipe is used.

like image 200
NathanOliver Avatar answered Oct 18 '25 13:10

NathanOliver


Specializations are irrelevant until the compiler knows which types it is going to use for the primary template.

When you write A<double>, then the compiler looks only at the primary template and sees that you actually mean A<double,void>.

And only then it is looking for specializations. Now, when your specialization is for A<double,int>, then it is not suitable because you asked for A<double,void>.

like image 22
j6t Avatar answered Oct 18 '25 14:10

j6t



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!