[英]Recursive class template and implicit instantiation error in C++
The following minimal reproducible example contains a template struct B
with default argument type containing a lambda A<[]{ return 1; }>
以下最小可重现示例包含一个模板
struct B
,其默认参数类型包含 lambda A<[]{ return 1; }>
A<[]{ return 1; }>
, B
is recursively inherited from B<>
. A<[]{ return 1; }>
, B
是从B<>
递归继承的。 And there is a specialization of B
for any A<z>
.并且对于任何
A<z>
都有B
的特化。
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: GCC 对这个例子没问题,Clang 抱怨:
error: implicit instantiation of template 'B<A<{}>>' within its own definition
Demo: https://gcc.godbolt.org/z/xzjzo7dE9演示: https://gcc.godbolt.org/z/xzjzo7dE9
Which compiler is right here?哪个编译器在这里?
PS If one modifies the definition of B
this way: PS 如果以这种方式修改
B
的定义:
template<class>
struct B : B<A<[]{ return 1; }>> {};
then all compilers become totally happy, demo: https://gcc.godbolt.org/z/roqnc39eq然后所有编译器都变得非常高兴,演示: https://gcc.godbolt.org/z/roqnc39eq
Which compiler is right here?
哪个编译器在这里?
Both are, since B
is ill-formed;两者都是,因为
B
是非良构的; NDR. NDR。 As always, [temp.res]/8 applies:
与往常一样, [temp.res]/8 适用:
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
(8.4) - 由于不依赖于模板参数的构造,紧随其定义的模板的假设实例化将是格式错误的,或者
The template is B
, and "its" definition here speaks of the primary.模板是
B
,这里的“它的”定义是主要的。 If we were to instantiate B<>
immediately after, we'll get an unconditionally ill-formed class definition.如果我们在之后立即实例化
B<>
,我们将得到一个无条件格式错误的 class 定义。 Hence, GCC and Clang can do whatever.因此,GCC 和 Clang 可以做任何事情。
Btw, this entire lambda as a template argument business is a red herring.顺便说一句,这整个 lambda 作为模板参数业务是一个红鲱鱼。 We can go for plain, old int as parameter and get similar divergence as well.
我们可以将 go 用于普通的旧 int 作为参数,并获得类似的分歧。
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 . Clang 仍然抱怨,但现在GCC 也是如此。
Yes, the original program is ill-formed due to https://timsong-cpp.github.io/cppwp/n4868/temp.res#general-8.4 .是的,由于https://timsong-cpp.github.io/cppwp/n4868/temp.res#general-8.4 ,原始程序格式错误。
One can fix it by moving the template specialization ahead:可以通过提前移动模板专业化来修复它:
template<auto>
struct A{};
template<class = A<[]{ return 1; }>>
struct B;
template<auto z>
struct B<A<z>> {};
template<class>
struct B : B<> {};
B<int> x;
which is accepted now by both Clang and GCC: https://gcc.godbolt.org/z/6TYdvTnMa现在 Clang 和 GCC 都接受了: https://gcc.godbolt.org/z/6TYdvTnMa
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.