在static_assert中使用std :: is_base_of由于不完整类型而失败

问题描述:

我想要做的是将一些类继承为extention类。事情是extention类必须知道它正在扩展的类。在static_assert中使用std :: is_base_of由于不完整类型而失败

这可以简单地实现这样的:

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

+1

您可以将'static_assert'放入成员函数中,但要使其正常工作,必须通过调用它来实现该函数。 – HolyBlackCat

+0

@HolyBlackCat把它放在构造函数中会起作用。不过,如果你有多个构造函数,它会是痛苦和容易出错的... – Amxx

+0

而不是使用静态断言敲击所有构造函数,而是从受保护的'Requiredived'派生模板'Extention'是'Self'选项?这会给你一个根保护的默认构造函数'RequiredBase()',在其中挂起你的静态断言。或者,也许我误解了你的目标。 – WhozCraig

缺少错误消息的我在做什么错?

由于[meta.rel]std::is_base_of要求派生类型是一个完整的类型:

如果BaseDerived都是非工会类类型,不属于同一类型的可能CV-合格版本, Derived应是完整的类型。

在另一侧,[class.mem/6]指出:

一类被认为是在类说明符的关闭}完全定义的对象类型(或完整的类型)。 [...]

这不是你的情况。当您实例化Extension<Foo>时,Foo本身远未完全定义。

换句话说,您不能在类作用域使用static_assert。如果你愿意的话,把它放在析构函数体内(我的首选解决方案,即使它有一些缺点)或任何其他(特殊)成员方法的正文。