【问题标题】:Why can't "is_base_of" be used inside a class declaration (incomplete type)?为什么不能在类声明(不完整类型)中使用“is_base_of”?
【发布时间】:2018-07-16 13:09:34
【问题描述】:

我完全明白为什么这个不能工作了:

class Base {};
class A;
static_assert(std::is_base_of<Base, A>::value, "");

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

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)

类型'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
};

应该不允许吗?

【问题讨论】:

  • the compiler already knows the 'class hierarchy' 是的,但是std::is_base_of 不是核心功能,而是功能,这让事情变得更加复杂。
  • @DeiDei:换句话说,“因为 C++ 是一个又一个巨大的抽象泄漏”? ;)
  • 目前 is_base_of 是一个非常普通的类模板。为了实现你的想法,你需要一个特殊的 is_base_of 魔术实现和标准的特殊权限来执行这个魔术。标准已经太大了。我们不想为了边际收益而让它变得更大更复杂。
  • 我们不想让它变得更大更复杂 @n.m.请为你自己说话:p 没有什么大魔法 - 只是逻辑 :) 如果一个特性不需要了解类的所有内容,只需要了解它的“类层次结构” - 为什么这样做..
  • 欢迎您提出建议。

标签: c++ static-assert incomplete-type


【解决方案1】:

在右大括号}之后,一个类定义是完整的(即,一个类被认为是定义的
在您的情况下,当您尝试将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, "");
};

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


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

class A : public Base {
    ~A() {
        static_assert(std::is_base_of<Base, A>::value, "");
    }
};

事实上,一个类类型在其成员函数体中被认为是完全定义的。


请参阅here 了解更多详情(强调我的):

类在类说明符的结束处被视为完全定义的对象类型([basic.types])(或完整类型)。 在类成员规范中,类在函数体中被认为是完整的、默认参数、无异常说明符和默认成员初始化器(包括嵌套类中的此类内容)。否则,它在其自己的类成员规范中被视为不完整。

【讨论】:

  • " 一个类类型被认为是在其成员函数的主体中完全定义的 " ...这是一个很好的、有见地的观点!
  • 参见here - 类在类说明符的结束处被视为完全定义的对象类型([basic.types])(或完整类型)。在类成员规范中,类在函数体、默认参数、noexcept 说明符和默认成员初始值设定项(包括嵌套类中的此类内容)中被认为是完整的。否则,它在其自己的类成员规范中被视为不完整。
【解决方案2】:

The doc pagestd::is_base_of 产生:

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

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


注意,static assertion 可以出现在块 命名空间/文件范围内。因此,您可以将其移到类的主体之外,或者,如果您不想将其放在标题中,请移至实现文件。

【讨论】:

  • 问题是问为什么会出现这种情况,而不仅仅是为了肯定它。
猜你喜欢
  • 2015-12-17
  • 2019-03-31
  • 2013-09-15
  • 2011-01-09
  • 2021-05-20
  • 1970-01-01
  • 1970-01-01
  • 2014-08-26
  • 2013-11-11
相关资源
最近更新 更多