CRTP 标准::is_default_constructible 无法按预期工作

CRTP std::is_default_constructible not working as expected

本文关键字:工作 constructible 标准 is default CRTP      更新时间:2023-10-16
template <class T>
class Base {
     static_assert(!std::is_default_constructible<T>::value,
                   "T must not be default constructible");
};
struct X1 : Base<X1> {};
struct X2 : Base<X2> {
   X2() = default;
};
struct X3 : Base<X3> {
   X3() {};
};
struct X4 : Base<X4> {
   X4() : Base{} {};
};
struct Y1 {};
int main() {
    // all compile. They shouldn't
    X1 x1; X2 x2; X3 x3; X4 x4; 
    // all compile. They shouldn't:
    Base<X1> bx1; Base<X2> bx2; Base<X3> bx3; Base<X4> bx4;  
    Base<Y1> by1; // static assert fires. This is the expected behavior
}

类级别的static_assert不会针对任何X类触发。但是开始Y(这不会派生Base

如果static_assert在构造函数内移动,它可以正常工作Base

如果is_default_constructible<T>源自Base,那么T在类级别总是错误的,原因是什么?

艾德酮

Base<X1>X1 的继承列表中实例化时,X1是不完整的类型。这意味着在检查类范围static_assert时,X1不是默认构造的。

Base的构造函数仅在使用时实例化,此时X1现在是一个完整的类型,并且是默认可构造的。这就是为什么static_assert在构造函数内部触发,但不在类范围内触发的原因。

根据

TartanLlama的回答,当T X时,T在类级别是不完整的。

我想在未定义的行为中添加这个结果T因为is_default_constructible必须是完整的类型:

适用于is_default_constructible的 CPP 首选项文档:

T 应为完整类型,(可能符合 cv 标准)无效,或阵列 未知边界。否则,行为是未定义的。