如何在成员函数中使用静态断言?

101*_*010 11 c++ inheritance static-assert

我有以下方案:

struct Baz {};
struct Qux {};

struct Base {
  virtual ~Base() {}
  virtual void foo() = 0;
};

template<typename T> struct Identity { static bool const value = false; };
template<typename T> void bar(T) { static_assert(Identity<T>::value, "Busted!!!"); }
template<> void bar<Baz>(Baz) {}

template<typename T>
struct Derived : Base {
  T m;
  void foo() { bar(m); }
};

int main() {
  Base *b0 = new Derived<Baz>;
  b0->foo();
  Base *b1 = new Derived<Qux>;
  (void) b1;
}
Run Code Online (Sandbox Code Playgroud)

也就是说,我有一个纯虚拟类Base和一个模板类Derived,它根据需要继承Base和覆盖纯虚函数foo.现在,foo我在里面调用函数模板bar.bar有专门的课程,Baz但没有课Qux.在main我试图实现Derived<Baz>一切物体的确定时.但是当我尝试实现Derived<Qux>编译器命中对象时static_assert.

问:

有没有办法以这样一种方式转换我的代码,即编译器Derived<Qux>只有在Derived<Qux>::foo()被调用时才会命中静态断言.

也就是说,实现一个对象Derived<Qux>将通过:

Base *b1 = new Derived<Qux>;
Run Code Online (Sandbox Code Playgroud)

但是当程序员稍后在代码中尝试调用时:

b1->foo(); // compile error static assert
Run Code Online (Sandbox Code Playgroud)

Sto*_*ica 10

标准在[temp.inst]/9上说了一个有趣的事情:

实现不应隐式实例化函数模板,变量模板,成员模板,非虚拟成员函数,成员类,类模板的静态数据成员或constexpr if语句的子语句,除非这样的实例化是必须的.如果虚拟成员函数不会被实例化,则实现是否隐式实例化类模板的虚拟成员函数是未指定的.

实例化虚拟功能的决定取决于实现,但只有在不需要的情况下才能实现.因此,我们面临的问题是:根据标准本身何时需要定义?

答案是[class.virtual]/11[temp.inst]/2:

在类中声明的虚函数应该在该类中定义或声明为纯,或者两者都是; 无需诊断

类模板特化的隐式实例化会导致声明的隐式实例化,而不会导致类成员函数的定义,默认参数或noexcept-specifiers的实例化.

因此,类模板的任何实例化都将实例化一个声明Derived::foo,通过连锁反应需要一个定义.因此,如果可用,定义也必须实例化.

实现可以在第一个引用段落中给出的余地的唯一方法是,如果它Derived::foo也是纯虚拟的.举个例子,ClangGCC都是这样做的.那当然可能对你的帮助有限.

所以长话短说,只要功能是虚拟的(而不是纯虚拟的),它就是一个不起作用的东西.