确保模板类不是多态的?

时间:2016-12-30 02:47:51

标签: c++ c++11 templates typetraits static-assert

我最近正在开发一个C ++库,我正在设计一个模板类,出于效率和安全原因,它需要特别是非多态的。为了确保以后我没有忘记这一点并且意外地破坏了一切,我认为我是一个好公民,并为此添加一个静态断言。

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

template <typename T> class VirtualVerboten {
     ...

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

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

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

但是因为这是一个模板类,所以制作一个&#34;模板static_assert&#34;不合法:

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();
}

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

是否有一个&#34;万无一失的&#34;在这里添加这个静态断言的方法?我理解为什么原始代码会产生错误以及为什么你不能有一个模板静态断言,所以这更像是一个&#34;我是否想念另一种方法呢?&#34;而不是一个&#34;这就是为什么你所做的不起作用。&#34;

2 个答案:

答案 0 :(得分:3)

@JerryCoffin's comment已经表明了这一点。最好的方法是在析构函数中使用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,另一种优雅的方式是创建一个实用程序类&amp;继承相同的,例如:

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>>
{
  // ...
};

答案 1 :(得分:0)

final关键字是C ++ 14的一项功能,它不允许继承类。如果继承该类,则代码将无法编译。例如:

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

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

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

编译器会抱怨