tags:

views:

83

answers:

4

I have a templated class

  template <typename T>
    class MyContainerClass

For types to be substituted for T, it has to satisfy many requirements: for example, get_id(), int data(), etc.

Obviously none of the fundamental types (PODs) are substitutable. One way I can provide this is via wrappers for the PODs that provide these functions. Is this an acceptable way?

Another way would be to change the template to:

template < typename T, typename C=traits<T> >
class MyContainerClass

and inside MyContainerClass, call traits::data() instead of data() on T objects. I will specialize traits<int>, traits<const char *> etc.

Is this good design ? How do I design such a traits class (completely static methods or allow for inheritance) ? Or are the wrapper classes a good solution?

What other alternatives are there?

+3  A: 

Another way to solve it would be to specialize the template for specific types, e.g.

template <>
    class MyContainerClass<int>

And then obviously implement everything needed to use the container with ints.

But I think the traits-solution is a lot better. It will also allow you to reuse the traits in other containers and other classes you make later.

Kleist
A: 

You'll observe that std uses type_traits quite extensively. You might check if they actually serve your needs, but also, this should be a good hint to you that a traits struct spec is the right way to go.

DeadMG
A: 

Even though everybody else seems to favor specialization, I'd go with traits. There's two reasons for that:

  1. They are the "use specialization"-idea in disguise, since they use specialization, too, but their idea is to externalize the specializations, so that they won't pollute your actual algorithms.

  2. Being used in the standard lib they are a well-proven and well-known technique everybody recognizes immediately. In contrast, specializations aren't used all that much in the std lib. (Did I just hear someone yelling std::vector<bool>?).

sbi
A: 

I'd favor traits too, for a different reason. Using sfinae, you can get a working is_class predicate :

template <typename T>
struct traits
{
    static const bool is_class = sizeof(test<T>(0)) == 1;

private:
    template <typename U> char (&test(int U::*))[1];
    template <typename> char (&test(...))[2];
};

and specialize on non-class types without having to enumerate all the basic types (which needs some dose of macros to be made maintainable...)

Alexandre C.