Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ traits example for this class

I haven't used the advanced features of C++ for a while and am refreshing my C++ knowledge.. Having said that, the concept 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?

like image 603
skyeagle Avatar asked Jan 21 '11 16:01

skyeagle


People also ask

What are traits in C?

What are traits in C/C++? Traits allow us to learn more information about a type. Using traits, an algorithm can change how it works depending on specific object traits, such as functions and variables. Traits are written in the form of a templated struct.

What is trait class in C++?

Traits classes do not determine the type of the object. Instead, they provide additional information about a type, typically by defining typedefs or constants inside the trait.


3 Answers

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.

like image 91
Frerich Raabe Avatar answered Oct 17 '22 18:10

Frerich Raabe


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.

like image 42
Flexo Avatar answered Oct 17 '22 17:10

Flexo


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.

like image 3
Karel Petranek Avatar answered Oct 17 '22 16:10

Karel Petranek