views:

226

answers:

2

Reading some source code, I have found next traits definition:

namespace dds {  
   template <typename Topic> struct topic_type_support { };
   template <typename Topic> struct topic_data_writer { };
   template <typename Topic> struct topic_data_reader { };
   template <typename Topic> struct topic_data_seq { };
}

#define REGISTER_TOPIC_TRAITS(TOPIC) \
namespace dds { \
   template<> struct topic_type_support<TOPIC> { \
      typedef TOPIC##TypeSupport type; }; \
   template<> struct topic_data_writer<TOPIC> { \
      typedef TOPIC##DataWriter type; }; \
   template<> struct topic_data_reader<TOPIC> { \
      typedef TOPIC##DataReader type; }; \
   template<> struct topic_data_seq<TOPIC> { \
      typedef TOPIC##Seq type; }; \
}

That looks weird to me. I would have grouped all the traits in a unique class like this:

namespace dds {
   template <typename Topic> struct topic_traits { };
}

#define REGISTER_TOPIC_TRAITS(TOPIC) \
namespace dds { \
   template<> struct topic_traits<TOPIC> { \
      typedef TOPIC##TypeSupport type_support; \
      typedef TOPIC##DataWriter data_writter; \
      typedef TOPIC##DataReader data_reader; \
      typedef TOPIC##Seq seq_type; \
   }; \
}

Can any of you figure out why second approach could be more fragile than the first one or significantly harder to add new traits?

+4  A: 

Having a single template class is now called a "traits blob". "Traits blob" are not recommended as they do not work well with meta-function (i.e. compile-time functions).

A meta-function is a template that takes a class and performs some operation on it. Something like:

template <class T>
class metafunction
{
    typename T::type value = ...;
}

You can then call the meta function for any of your traits by doing:

metafunction<topic_type_support<int> >::value;
metafunction<topic_data_writer<int> >::value;

You would not be able to call the meta-function with your traits blob class because there is now way to tell the metafunction which typedef to use.

If you want to learn more about meta-functions, I recommend the book C++ Template Metaprogramming.

R Samuel Klatchko
For more on meta programing google Boost MPL
KitsuneYMG
@Samuel: Traits blob. That is the name I was looking for! Thanks. I have already ordered Abrahams book.
fnieto
+1  A: 

It's a matter of style. Your example is probably more maintainable, but having separate types does confer the advantage that they're independent - you could easily specialize, say, topic_data_reader for all pointer types, but leave the others unspecialized.

If you want to go deeper, I'd question the lack of defaults:

namespace dds {
  template <typename Topic> struct topic_traits {
    typedef typename Topic::type_support type_support;
    typedef typename Topic::data_writer data_writer;
    typedef typename Topic::data_reader data_reader;
    typedef typename Topic::seq_type seq_type;
  };
}

This approach means that any class providing the requisite typedefs automatically qualifies. A macro could still be used to generate those typedefs or specialize the class, but that's probably not necessary (seq_type in particular looks suspiciously like it's typically a typedef, not a user-defined type).

EDIT: With a larger traits class, separating things out can be used to reduce the number of instantiations required, but if your traits class has elements where using one probably means you're using the others, this adds no benefit.

coppro