为什么不能在类声明中使用"is_base_of"(不完整类型)?

use*_*762 13 c++ static-assert incomplete-type

我完全明白为什么这不能正常工作:

class Base {};
class A;
static_assert(std::is_base_of<Base, A>::value, "");
Run Code Online (Sandbox Code Playgroud)

因为没有关于"类层次结构"的信息,但是......为什么以下不能工作?

class Base {};
class A : public Base {
    static_assert(std::is_base_of<Base, A>::value, "");
};
(produce: an undefined class is not allowed as an argument to compiler intrinsic type trait)
Run Code Online (Sandbox Code Playgroud)

类型'A'仍然没有与static_assert一致(根据这个概念的定义).但是 - 编译器已经知道'类层次结构'并且可以为此提供答案.

当然 - 这个static_assert可以移动到析构函数或其他什么来解决这个问题,但有些情况下无法完成,例如:

class Base {};

template<typename T>
struct type_of {
    static_assert(std::is_base_of<Base, T>::value, "T is not derived from Base");
    using type = int; //* Some normal type in real use
};

class A : public Base {
public:
    type_of<A>::type foo(); // Will not compile
};
Run Code Online (Sandbox Code Playgroud)

不应该被允许吗?

sky*_*ack 16

在结束括号之后,类定义是完整的(即,类被认为是定义的)}.
在您的情况下,当您尝试使用Astd::is_base_of,A尚未完全定义:

class A : public Base {
    // no closing brace for A yet, thus A isn't fully defined here
    static_assert(std::is_base_of<Base, A>::value, "");
};
Run Code Online (Sandbox Code Playgroud)

另一方面,std::is_base_of需要完全定义的类型才能工作.
因此错误.


作为一种解决方法,您可以将断言放在析构函数中A:

class A : public Base {
    ~A() {
        static_assert(std::is_base_of<Base, A>::value, "");
    }
};
Run Code Online (Sandbox Code Playgroud)

实际上,类类型在其成员函数体中被认为是完全定义的.


有关详细信息,请参阅此处(强调我的):

在类说明符的结束时,类被认为是完全定义的对象类型([basic.types])(或完整类型).在类成员规范中,该类在函数体,默认参数,noexcept-specifiers和默认成员初始化器(包括嵌套类中的这类事物)中被视为完整.否则,它在其自己的类成员规范中被视为不完整.

  • “ _a类类型被认为是在其成员函数的bodys中完全定义的”“ ...这是一个很好的见解! (2认同)

Mat*_*jek 7

该文档页面std::is_base_of收益:

如果Base和Derived都是非联合类类型,并且它们不是同一类型(忽略cv-qualification),则Derived应为完整类型 ; 否则行为未定义.

使用后关闭其范围后,类的定义已完成}.因此,在您的情况下,会生成错误.


请注意,静态断言可以出现在块命名空间/文件范围中.因此,您可以将它移到类的主体外部,或者,如果您不想在标题中将它移动到其中,请转到实现文件.

  • 问题是问为什么会出现这种情况,而不仅仅是为了肯定事实如此。 (3认同)