我暂时没有使用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'的子类呢?
答案 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)
类型特征和基于策略的编程是不同的主题。类型特征添加有关不能包含额外信息的现有类型和类型的新信息(任何内置)。基于策略的设计是一种设计类的方法,以便您可以以各种方式组装它们以创建不同的行为;它是一种编译时状态模式。