我有这些类(class):
#include <type_traits>
template <typename T>
class A {
public:
static_assert(std::is_default_constructible_v<T>);
};
struct B {
struct C {
int i = 0;
};
A<C> a_m;
};
int main() {
A<B::C> a;
}
编译时,
a_m
不是默认可构造的,但 a
是。更改时
C
到:struct C {
int i;
};
一切安好。
使用 Clang 9.0.0 测试。
最佳答案
标准文本和评论中指出的几个主要实现都不允许这样做,但出于完全不相关的原因。
一、“by the book”原因:A<C>
的实例化点是,根据标准,immediately before the definition of B
,以及 std::is_default_constructible<C>
的实例化点在此之前:
For a class template specialization, [...] if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.
自
C
在这一点上显然是不完整的,实例化 std::is_default_constructible<C>
的行为未定义。但是,请参阅 core issue 287 ,这将改变这个规则。实际上,这与 NSDMI 有关。
= 0
原则上可以引用B
中的东西尚未声明,因此实现无法真正尝试解析它,直到它完成 B
. C
没有声明构造函数。 A<C>
时,它认为C
不完整。 整个处理延迟解析区域的区域都没有详细说明,伴随着实现的分歧。可能需要一段时间才能清理干净。
关于c++ - 为什么我的类不可默认构造?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60307207/