Определение признаков типа. Капли признаков и метафункции

Читая исходный код, я нашел следующее определение признаков:

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; }; \
}

Мне это кажется странным. Я бы сгруппировал все черты в уникальный класс следующим образом:

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; \
   }; \
}  

Может ли кто-нибудь из вас понять, почему второй подход может быть более хрупким, чем первый, или значительно сложнее добавить новые черты?


person fnieto - Fernando Nieto    schedule 08.12.2009    source источник


Ответы (2)


Наличие одного класса шаблона теперь называется «большим двоичным объектом признаков». "Traits blob" не рекомендуются, так как они плохо работают с метафункциями (т.е. с функциями времени компиляции).

Мета-функция — это шаблон, который берет класс и выполняет над ним некоторую операцию. Что-то типа:

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

Затем вы можете вызвать метафункцию для любой из ваших черт, выполнив следующие действия:

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

Вы не сможете вызвать метафункцию с вашим классом BLOB-объектов признаков, потому что теперь есть способ сообщить метафункции, какой typedef использовать.

Если вы хотите узнать больше о метафункциях, я рекомендую книгу Метапрограммирование шаблонов C++.

person R Samuel Klatchko    schedule 08.12.2009
comment
@Samuel: Черты капли. Это имя я искал! Спасибо. Я уже заказал книгу Абрахамса. - person fnieto - Fernando Nieto; 12.12.2009

Это вопрос стиля. Ваш пример, вероятно, более удобен в сопровождении, но наличие отдельных типов дает то преимущество, что они независимы - вы можете легко специализировать, скажем, topic_data_reader для всех типов указателей, но оставить другие неспециализированными.

Если вы хотите углубиться, я бы поставил под сомнение отсутствие значений по умолчанию:

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;
  };
}

Этот подход означает, что любой класс, предоставляющий необходимые определения типов, автоматически квалифицируется. Макрос все еще можно использовать для создания этих определений типов или специализации класса, но это, вероятно, не обязательно (в частности, seq_type выглядит подозрительно, как будто это обычно определение типа, а не пользовательский тип).

РЕДАКТИРОВАТЬ: с более крупным классом признаков можно использовать разделение вещей, чтобы уменьшить количество требуемых экземпляров, но если в вашем классе свойств есть элементы, где использование одного, вероятно, означает, что вы используете другие, это не добавляет никакой пользы.

person coppro    schedule 08.12.2009