14

我已经有一段时间没有使用 C++ 的高级特性了,并且正在刷新我的 C++ 知识。话虽如此,特征和基于策略的编程的概念是我从未真正设法理解的东西。

我想改变它。我正在编写一个通用容器。我想强制执行一个策略,即容器将只存储从特定基类派生的类。这是因为当尝试访问向量边界之外的项目时,容器会返回一个无效对象(而不是抛出)。

template <class T>   
class GenericContainer
{
private:
    typedef std::vector<T> TypeVect;
    void addElement(const T& elem);

    TypeVect m_elems;

public:
    unsigned int size() const;
    T& elementAt(const unsigned int pos);
    const T elementAt(const unsigned int pos) const;
};

我将如何使用特征来限制这个通用容器只包含类“ContainerItem”的子类?

4

4 回答 4

12

你可以使用一个小IsDerivedFrom模板,它只能在给定类型“D”继承另一个类型“B”的情况下被实例化(这个实现取自一篇不错的 Guru Of The Week 文章):

template<typename D, typename B>
class IsDerivedFrom
{
  static void Constraints(D* p)
  {
    B* pb = p; // this line only works if 'D' inherits 'B'
    pb = p; // suppress warnings about unused variables
  } 

protected:
  IsDerivedFrom() { void(*p)(D*) = Constraints; }
}; 

// Force it to fail in the case where B is void
template<typename D>
class IsDerivedFrom<D, void>
{
  IsDerivedFrom() { char* p = (int*)0; /* error */ }
};

您现在可以IsDerivedFrom使用继承简单地实例化模板:

template <class T>   
class GenericContainer : public IsDerivedFrom<T, ContainerItem>
{
    ...
};

此代码仅在T继承时编译ContainerItem

于 2011-01-21T16:21:33.317 回答
5

您可以使用boost::mpl在编译时断言类型从基类继承来强制执行此操作。

“自己动手”相当简单:

template <typename D, typename B>
class is_derived_from {
   class No { };
   class Yes { No no[2]; };

   static Yes Test(B*);
   static No  Test(...);
public:
   enum { inherits = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };
   static bool is_derived() { return inherits; }
};

我认为这最初来自 GoTW。你所需要的只是一个合适的断言机制(编译时间可能更好)。通常的技巧是创建一个宏,使一个负大小的数组使断言失败或 1 传递它。

于 2011-01-21T16:18:17.723 回答
3

我认为您正在寻找概念检查。这将被内置到 C++0x 中,但已被推迟。Boost 库包含一个用于管理概念的库,但它远非语法糖果。

旁注:小心容器中的对象切片。如果您希望允许将基类和派生类都存储在容器中,请使用指针而不是对象本身。

于 2011-01-21T16:19:24.770 回答
2

类型特征和基于策略的编程是不同的主题。类型特征添加有关现有类型和不能包含额外信息(任何内置)的类型的新信息。基于策略的设计是一种设计类的方法,以便您可以以各种方式组装它们以创建不同的行为;这是一种编译时状态模式。

于 2011-01-21T17:37:03.673 回答