2009-12-08 32 views
7

Leggendo qualche codice sorgente, ho trovato tratti prossima definizione:Definizione di tratti di tipo. Tratti blob & METAFUNCTIONS

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

che sembra strano per me. Avrei raggruppato tutte le caratteristiche di una classe unica come questa:

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

Chi di voi a capire perché secondo approccio potrebbe essere più fragile rispetto al primo o significativamente più difficile aggiungere nuovi tratti?

risposta

5

Avere una singola classe template ora è chiamata "bits di tratti". I "blob dei tratti" non sono raccomandati in quanto non funzionano bene con la meta-funzione (cioè le funzioni di compilazione).

Una meta-funzione è un modello che accetta una classe e esegue alcune operazioni su di essa. Qualcosa di simile:

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

È quindi possibile chiamare la funzione meta per le tue caratteristiche facendo:

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

Non sarebbe in grado di chiamare la meta-funzione con la classe tratti blob perché ci è ora il modo di dire alla metafunzione quale typedef usare.

Se vuoi saperne di più sulle meta-funzioni, consiglio il libro C++ Template Metaprogramming.

+0

Per ulteriori informazioni sulla meta programmazione google Boost MPL – KitsuneYMG

+0

@ Samuel: Tracce di blob. Questo è il nome che stavo cercando! Grazie. Ho già ordinato il libro di Abrahams. –

1

È una questione di stile. Il tuo esempio è probabilmente più gestibile, ma avere tipi separati conferisce il vantaggio di essere indipendenti: potresti facilmente specializzarti, ad esempio, topic_data_reader per tutti i tipi di puntatore, ma lascia gli altri non specializzati.

Se si vuole andare più a fondo, mi piacerebbe in discussione la mancanza di default:

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

Questo approccio significa che ogni classe che fornisce le necessarie typedef qualifica automaticamente. Una macro può ancora essere utilizzata per generare quei typedef o specializzare la classe, ma probabilmente non è necessario (seq_type in particolare sembra sospetto che di solito è un typedef, non un tipo definito dall'utente).

MODIFICA: con una classe di caratteri più ampia, la separazione delle cose può essere utilizzata per ridurre il numero di istanze richieste, ma se la classe dei tratti contiene elementi in cui l'uso probabilmente significa che si stanno utilizzando gli altri, ciò non apporta alcun vantaggio.