【问题标题】:using std::is_base_of in static_assert fails due to incomplete type由于类型不完整,在 static_assert 中使用 std::is_base_of 失败
【发布时间】:2017-08-12 18:03:01
【问题描述】:

我想要做的是让一些类继承 extention 类。问题是extention 类必须知道它正在扩展哪个类。

这可以简单地实现如下:

template<typename Self>
class Extention
{
    public:
        void check() const
        {
            std::cout << "Extention is valid: "
                      << std::boolalpha
                      << std::is_base_of<Extention, Self>::value
                    << std::endl;
        }
};
class Foo : public Extention<Foo> {};
class Bar : public Extention<void> {};

FooBar 类显示了扩展的好坏用法。

Foo().check(); → Extention is valid: true
Bar().check(); → Extention is valid: false

我想在编译的时候检查模板的有效性,这才带我写

template<typename Self>
class Extention
{
    static_assert(std::is_base_of<Extention, Self>::value);
};

但是,gcc 告诉我这个 static_assert 是错误的,因为 class Foo 的类型不完整。

我做错了什么?

编辑:我使用的是-std=c++17,错误不是static_assert中缺少错误信息

【问题讨论】:

  • 您可以将static_assert 放入成员函数中,但要使其工作,您必须实例化该函数(可能通过调用它)。
  • @HolyBlackCat 将其放入构造函数中会起作用。尽管如此,如果您有多个构造函数,这将是痛苦且容易出错的......
  • 不是用静态断言打击所有构造函数,而是从受保护的Requiredived 派生模板ExtentionSelf 一个选项吗?这将为您提供一个受根保护的默认构造函数RequiredBase(),在其中挂起您的静态断言。或者我在这里误解了你的目标。
  • 那么把它放到析构函数中怎么样?
  • @WhozCraig:会工作,但过度设计。 HolyBlackCat:工作起来更优雅。尽管如此,我们应该能够将断言直接放入类中......

标签: c++ templates inheritance static-assert


【解决方案1】:

我做错了什么?

因为[meta.rel]std::is_base_of 要求派生类型是完整类型:

如果BaseDerived 是非联合类类型并且可能不是同一类型的 cv 限定版本,则Derived 应是完整类型。

另一方面,[class.mem/6] 表示:

在类说明符的结尾} 处,类被视为完全定义的对象类型(或完整类型)。 [...]

那不是你的情况。当您实例化Extension&lt;Foo&gt; 时,Foo 本身远未完全定义。

换句话说,您不能在类范围内使用 static_assert。如果您愿意,可以将其放入析构函数的主体(实际上是我更喜欢的解决方案,尽管它有一些缺点)或任何其他(特殊)成员方法的主体。

【讨论】:

    猜你喜欢
    • 2019-10-29
    • 1970-01-01
    • 2018-07-16
    • 2016-04-12
    • 1970-01-01
    • 1970-01-01
    • 2020-02-23
    • 2019-05-13
    • 2014-07-21
    相关资源
    最近更新 更多