C ++描述了这个类的示例

时间:2011-01-21 16:10:35

标签: c++ templates traits

我暂时没有使用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;
};

我如何使用traits来限制这个泛型容器只包含类'ContainerItem'的子类呢?

4 个答案:

答案 0 :(得分:12)

您可以使用一个小IsDerivedFrom模板,只有在给定类型“D”继承另一个类型“B”(此实现取自nice Guru Of The Week article)时才能实例化:

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时才会编译。

答案 1 :(得分: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。您所需要的只是一个合适的断言机制(编译时间可能更好)。通常的技巧是创建一个宏,使得一个负数大小的数组使assert失败,或者1传递它。

答案 2 :(得分:3)

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

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

答案 3 :(得分:2)

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