我有那些课程:
#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测试。
按书:A<C>
的实例化点是immediately before the definition of B
,而B
的实例化点紧接在此之前:
对于类模板专业化,如果专业化是隐式实例化,因为它是从另一个内部引用的模板专业化,如果专业化所来自的上下文被引用取决于模板参数,以及没有在实例化之前实例化专门化封闭模板,实例化点是立即在封闭模板的实例化点之前。否则,这种专业化的实例化点紧接在名称空间范围声明或定义之前指的是专业化。
由于std::is_default_constructible<C>
在那时显然是不完整的,因此实例化C
的行为是不确定的。但是,请参见std::is_default_constructible<C>
。
实际上:
= 0
中尚未声明的内容,因此实现在完成B
之前无法真正尝试解析它。B
没有声明构造函数。C
它是:
如果上述模板的实例直接或直接取决于间接地,对于不完整的类型,该实例化可以产生如果假设该类型已完成,则结果会不同,行为是不确定的。