I haven't used the advanced features of C++ for a while and am refreshing my C++ knowledge.. Having said that, the conce开发者_运维知识库pt of traits and policy based programming was something that I never really managed to get my head around.
I want to change that. I am writing a generic container. I want to enforce a policy that the container will store only classes that derive from a particular base class. This is because the container returns an invalid object (instead of throwing) when an attempt is made to access an item outside the vector bounds.
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;
};
How would I use traits to restrict this generic container to contain only subclasses of class 'ContainerItem' say?
You can use a little IsDerivedFrom
template which can only be instantiated in case a given type 'D' inherits another type 'B' (this implementation was taken from a 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 */ }
};
You can now simply instantiate the IsDerivedFrom
template using inheritance:
template <class T>
class GenericContainer : public IsDerivedFrom<T, ContainerItem>
{
...
};
This code only compiles if T
inherits ContainerItem
.
You can enforce this using boost::mpl to assert at compile time that a type inherits from a base.
The "roll your own" is fairly simple:
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; }
};
I think this came from GoTW originally. All you need then is a suitable assert mechanism (compile time is probably nicer). The usual trick to this is to create a macro that makes an array with negative size to fail the assert or 1 to pass it.
I think you are looking for concept checking. This was about to be built in to C++0x but it has been postponed. The Boost libraries contain a library for managing concepts but it's far from being a syntax candy.
Side note: Be careful about object slicing in your container. In case you want to allow both base and derived classes to be stored in the container, use pointers instead of the objects itself.
Type traits and policy based programming are distinct topics. Type traits add new information about existing types and types that can't contain extra information (any builtin). Policy based design is a method of designing classes so that you can assemble them in various ways to create different behaviors; it's sort of a compile-time state pattern.
精彩评论