【问题标题】:Ensuring a template class isn't polymorphic?确保模板类不是多态的?
【发布时间】:2016-12-30 02:47:51
【问题描述】:

我最近在一个 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.");

但由于这是一个模板类,因此制作“模板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();
}

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

是否有一种“万无一失”的方法可以在此处添加此静态断言?我理解为什么原始代码会产生错误以及为什么不能有模板静态断言,所以这更像是“我错过了另一种方法吗?”而不是“这就是为什么你所做的不起作用。”

【问题讨论】:

  • 呃?构造函数?必须以某种方式在某个地方构建类。把你的静态断言塞进去。
  • @SamVarshavchik 这就是我最终要做的。也许我应该编辑问题以使其更清楚。
  • 您只需要将类型封装在依赖项中,因此仅在第二阶段检查静态断言。
  • @KerrekSB 你能在这里发布类似的答案吗?
  • 似乎 dtor 可能是一个更好的选择。只有其中一个需要担心(即没有重载)。

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


【解决方案1】:

@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,另一种优雅的方法是创建一个实用程序类并继承它,例如:

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

【讨论】:

    【解决方案2】:

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

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

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

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

    编译器会抱怨

    【讨论】:

    • 问题是关于多态性,而不是继承。的确,两者非常密切相关,但是没有多态性的继承(即使用虚函数)是可能的。 cppreference 将is_polymorphic 类型特征描述为a non-union class that declares or inherits at least one virtual function。这应该提供有关 OP 试图排除的类类型的线索。
    • 奇怪的是,在我考虑使用继承但不必使用多态性的情况下,这种方法实际上不适用于我的情况。
    猜你喜欢
    • 2012-12-26
    • 1970-01-01
    • 2010-12-05
    • 2017-02-09
    • 2013-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多