简体   繁体   English

递归 class 模板和 C++ 中的隐式实例化错误

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM