确保模板 class 不是多态的?

Ensuring a template class isn't polymorphic?

我最近在开发一个 C++ 库,我在其中设计了一个模板 class,出于效率和安全原因,该模板需要特别是非多态的。为了确保以后我不会忘记这一点而无意中破坏了一切,我想我会做一个好公民并为此添加一个静态断言。

我最初尝试过这样的事情:

template <typename T> class VirtualVerboten {
     ...

     static_assert(!std::is_polymorphic<VirtualVerboten>::value,
                   "This should not be polymorphic."); // Error!
};

这无法编译,因为在我使用 VirtualVerboten 时,它是一个不完整的类型。如果这是一个非模板 class,我只是将 static_assert 放在类型之后:

class NonTemplateVirtualVerboten {
   ...
}
static_assert(!std::is_polymorphic<NonTemplateVirtualVerboten>::value,
              "This should not be polymorphic.");

但是因为这是一个模板 class,所以制作 "template static_assert" 的类似想法是不合法的:

template <typename T> class VirtualVerboten {
     ...

};

template <typename T>              
static_assert(!std::is_polymorphic<VirtualVerboten>::value,
              "This should not be polymorphic."); // Error!

我想到的解决方案是在 VirtualVerboten 中找到一个可能在实例化模板时使用的成员函数(特别是构造函数),然后将静态断言放在那里:

template <typename T> class VirtualVerboten {
     VirtualVerboten();
};

template <typename T>
VirtualVerboten<T>::VirtualVerboten() {
  static_assert(!std::is_polymorphic<VirtualVerboten>::value,
                "This should not be polymorphic."); // Yay!
  doSomeActualThingsAtRuntime();
}

这是有效的,除了它依赖于这样一个事实,即这个特定的构造函数将被实际调用并因此被实例化,如果有多个构造函数可以被调用,它就会失败。

是否有 "foolproof" 方法可以在此处添加此静态断言?我理解为什么原始代码会产生错误以及为什么不能有模板静态断言,所以这更像是 "did I miss another way of doing this?" 而不是 "here's why what you did doesn't work."

final 关键字是一个 C++14 特性,它不允许 classes 被继承。如果 class 被继承,代码将无法编译。示例:

template <typename T>
class VirtualVerboten final {
  ...
}

如果有人试图继承它...

class Derived : public VirtualVerboten<int> {
  ...
}

编译器会报错

已经指出了。最好的方法是在析构函数中使用 static_assert。即

template <typename T> 
class VirtualVerboten {
public: 
  ~VirtualVerboten() {
    static_assert(!std::is_polymorphic<VirtualVerboten>::value,
                  "This should not be polymorphic.");
   }
};

因为析构函数只能是 1,所以保证只要实例化它的对象就会检查 static_assert


IMO,另一种优雅的方法是创建一个实用程序 class 并继承它,例如:

template<typename T>
struct NonPolymorphic
{
  ~NonPolymorphic() 
  { static_assert(!std::is_polymorphic<T>::value, "This should not be polymorphic."); }
};

template <typename T> 
class VirtualVerboten : NonPolymorphic<VirtualVerboten<T>>
{
  // ...
};