The question may be too hard to describe in on sentence in the title, but here is a minimal example:
#include <iostream>
#include <type_traits>
template <class T, class U, class Enabler>
struct my_trait : std::false_type
{};
template <class T, class U>
struct my_trait<T, U,
std::enable_if_t<std::is_same<T, U>::value>> : std::true_type
{};
template <class T>
class temped
{};
template <class T>
struct my_trait<temped<T>, temped<T>, void> : std::false_type
{};
template <class T, class U>
using trait_t = my_trait<T, U, void>;
int main()
{
std::cout << std::boolalpha;
std::cout << trait_t<int, float>::value << std::endl; // false
std::cout << trait_t<int, int>::value << std::endl; // true
// Compilation error: Ambiguous
//std::cout << trait_t<temped<int>, temped<int>>::value << std::endl;
return 0;
}
(also available on godbolt)
Basically, we have a base template class my_trait
taking two types (and a dummy type for specialization purposes), with two partial specializations:
temped
class template for the same typeNaïvely, we would have expected the second partial specialization not to be ambiguous with the first, as it feels "more specialized", putting more restriction on the deduced types for T
and U
on the base template.
Yet major compilers seems to agree that we were wrong with our expectations: why is it not considered more specialized?
@super's now-deleted answer got this basically right. std::enable_if_t<...>
is not void
in partial ordering; as a dependent type it can in principle be something completely arbitrary. It effectively is considered a completely unique type for partial ordering purposes.
As a result of this mismatch, the deduction during partial ordering fails in both directions, and the specializations are ambiguous.
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