C++ 中的递归 class 模板和隐式实例化错误
Recursive class template and implicit instantiation error in C++
以下最小可重现示例包含模板 struct B
,默认参数类型包含 lambda A<[]{ return 1; }>
,B
递归继承自 B<>
。任何 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 可以接受这个例子,Clang 抱怨说:
error: implicit instantiation of template 'B<A<{}>>' within its own definition
演示:https://gcc.godbolt.org/z/xzjzo7dE9
这里是哪个编译器?
P.S。如果这样修改 B
的定义:
template<class>
struct B : B<A<[]{ return 1; }>> {};
然后所有编译器都变得非常开心,演示:https://gcc.godbolt.org/z/roqnc39eq
Which compiler is right here?
两者都是,因为 B
格式错误; NDR。一如既往,[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
模板是B
,这里的“它的”定义是指主要的。如果我们在之后立即实例化 B<>
,我们将得到一个无条件格式错误的 class 定义。因此,GCC 和 Clang 可以为所欲为。
顺便说一句,这整个 lambda 作为模板参数业务是一个转移注意力的问题。我们可以使用普通的、旧的 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 仍然抱怨,但现在 so does GCC。
是的,由于https://timsong-cpp.github.io/cppwp/n4868/temp.res#general-8.4,原始程序格式错误。
可以通过向前移动模板专业化来修复它:
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;
现在被 Clang 和 GCC 接受:https://gcc.godbolt.org/z/6TYdvTnMa
以下最小可重现示例包含模板 struct B
,默认参数类型包含 lambda A<[]{ return 1; }>
,B
递归继承自 B<>
。任何 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 可以接受这个例子,Clang 抱怨说:
error: implicit instantiation of template 'B<A<{}>>' within its own definition
演示:https://gcc.godbolt.org/z/xzjzo7dE9
这里是哪个编译器?
P.S。如果这样修改 B
的定义:
template<class>
struct B : B<A<[]{ return 1; }>> {};
然后所有编译器都变得非常开心,演示:https://gcc.godbolt.org/z/roqnc39eq
Which compiler is right here?
两者都是,因为 B
格式错误; NDR。一如既往,[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
模板是B
,这里的“它的”定义是指主要的。如果我们在之后立即实例化 B<>
,我们将得到一个无条件格式错误的 class 定义。因此,GCC 和 Clang 可以为所欲为。
顺便说一句,这整个 lambda 作为模板参数业务是一个转移注意力的问题。我们可以使用普通的、旧的 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 仍然抱怨,但现在 so does GCC。
是的,由于https://timsong-cpp.github.io/cppwp/n4868/temp.res#general-8.4,原始程序格式错误。
可以通过向前移动模板专业化来修复它:
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;
现在被 Clang 和 GCC 接受:https://gcc.godbolt.org/z/6TYdvTnMa