Are multiple class template specialisations valid, when each is distinct only between patterns involving template parameters in non-deduced contexts?
A common example of std::void_t
uses it to define a trait which reveals whether a type has a member typedef
called "type". Here, a single specialisation is employed. This could be extended to identify say whether a type has either a member typedef
called "type1", or one called "type2". The C++1z code below compiles with GCC, but not Clang. Is it legal?
template <class, class = std::void_t<>>
struct has_members : std::false_type {};
template <class T>
struct has_members<T, std::void_t<typename T::type1>> : std::true_type {};
template <class T>
struct has_members<T, std::void_t<typename T::type2>> : std::true_type {};
There is a rule that partial specializations have to be more specialized than the primary template - both of your specializations follow that rule. But there isn't a rule that states that partial specializations can never be ambiguous. It's more that - if instantiation leads to ambiguous specialization, the program is ill-formed. But that ambiguous instantiation has to happen first!
It appears that clang is suffering from CWG 1558 here and is overly eager about substituting in.void
forstd::void_t
This is CWG 1980 almost exactly:
If you use the non-alias implementation of
void_t
:then clang allows the two different specializations. Sure, instantiating
has_members
on a type that has bothtype1
andtype2
typedefs errors, but that's expected.