The following minimal reproducible example contains a template struct B with default argument type containing a lambda A<[]{ return 1; }>, B is recursively inherited from B<>. And there is a specialization of B for any A<z>.
template<auto>
struct A{};
template<class = A<[]{ return 1; }>>
struct B : B<> {};
template<auto z>
struct B<A<z>> {};
B<int> x;
GCC is ok with the example, by Clang complains:
error: implicit instantiation of template 'B<A<{}>>' within its own definition
Demo: https://gcc.godbolt.org/z/xzjzo7dE9
Which compiler is right here?
P.S. If one modifies the definition of B this way:
template<class>
struct B : B<A<[]{ return 1; }>> {};
then all compilers become totally happy, demo: https://gcc.godbolt.org/z/roqnc39eq
CodePudding user response:
Which compiler is right here?
Both are, since B is ill-formed; NDR. As always, [temp.res]/8 applies:
The validity of a template may be checked prior to any instantiation. The program is ill-formed, no diagnostic required, if:
(8.4) - a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, or
The template is B, and "its" definition here speaks of the primary. If we were to instantiate B<> immediately after, we'll get an unconditionally ill-formed class definition. Hence, GCC and Clang can do whatever.
Btw, this entire lambda as a template argument business is a red herring. We can go for plain, old int as parameter and get similar divergence as well.
template<int>
struct A{};
template<class = A<0>>
struct B : B<> {};
template<int z>
struct B<A<z>> {};
B<int> x;
int main() {}
Clang still complains, but now so does GCC.
