2010-10-29 58 views
2

Je voudrais vous demander un conseil sur le modèle de fonction. J'ai une fonction qui ajoute des données dans le tampon. Mais j'ai aussi besoin d'ajouter une information sur le type de données dans le tampon. Le type de données est un ENUM suivant:Détermination du type dans le modèle de fonction

enum ParameterType 
{ 
    UINT, 
    FLOAT, 
    DOUBLE 
}; 

Et je dois créer un modèle de fonction de la fonction comme ceci:

void SomeBuffer::append(double par) 
{ 
    appendType(DOUBLE); 
    memcpy(pStr + _length, &par, sizeof(double)); 
    _length += sizeof(double); 
    appendType(DOUBLE); 
} 

Pourriez-vous s'il vous plaît me conseiller comment passer une valeur de ParameterType pour appendType() en fonction du type de paramètre.

template<class T> 
void SomeBuffer::append(T par) 
{  
    appendType(???); 
    memcpy(pStr + _length, &par, sizeof(T)); 
    _length += sizeof(T); 
    appendType(???); 
} 

J'ai essayé de le faire avec certaines macros mais sans succès. Merci beaucoup pour tout conseil.

+1

Avertissement: La sérialisation de choses avec 'memcpy()' va vous causer des problèmes si la machine qui lit le tampon a une endianité différente de celle de la machine qui écrit le tampon. –

Répondre

4
template <typename T> struct identity { }; 

inline void appendType_(identity<double> ) { appendType(DOUBLE); } 
inline void appendType_(identity<unsigned>) { appendType(UINT); } 
inline void appendType_(identity<MyType> ) { appendType(MY_TYPE); } 

utiliser ensuite comme si:

template<class T> 
void SomeBuffer::append(T par) 
{  
    appendType_(identity<T>()); 
    memcpy(pStr + _length, &par, sizeof(T)); 
    _length += sizeof(T); 
    appendType_(identity<T>()); 
} 

Vous pouvez également combiner avec l'idée de @ Vitaut d'obtenir le code de type séparément, et à appendType passer.

inline ParameterType typeCode(identity<double> ) { return DOUBLE; } 
inline ParameterType typeCode(identity<unsigned>) { return UINT; } 
inline ParameterType typeCode(identity<MyType> ) { return MY_TYPE; } 
... 
appendType(typeCode(identity<T>())); 

EDIT: Merci à @Johannes pour la suggestion identity<T>.

+0

Dans ce cas, les surcharges simples peuvent être plus sensées que les spécialisations complètes. Voir http://www.gotw.ca/publications/mill17.htm – Flexo

+0

@awoodland: Merci pour le conseil. Je venais d'arriver à cette réalisation lorsque votre commentaire a surgi. –

+0

Cette solution a le problème que, en raison de promotions lors de l'appel 'appendType_' ou' typeCode', un code de type incorrect est inséré, par exemple lorsqu'on appelle 'append' pour un type de classe qui a une conversion implicite en' unsigned int'. –

7

Vous pouvez faire ce que vous voulez en introduisant un modèle de classe supplémentaire qui tracera le type à la constante de l'énumération que vous avez besoin comme dans l'exemple suivant (sans jeu par souci de concision):

enum ParameterType 
{ 
    UINT, 
    DOUBLE 
}; 

template <typename T> 
struct GetTypeCode; 

template <> 
struct GetTypeCode<double> 
{ 
    static const ParameterType Value = DOUBLE; 
}; 

template <> 
struct GetTypeCode<unsigned> 
{ 
    static const ParameterType Value = UINT; 
}; 

template <typename T> 
void SomeBuffer::append(T par) 
{ 
    appendType(GetTypeCode<T>::Value); 
    memcpy(pStr + _length, &par, sizeof(T)); 
    _length += sizeof(T); 
    appendType(GetTypeCode<T>::Value); 
} 

Depuis spécialisations GetTypeCode sera presque identique, vous pouvez introduire une macro pour les définir, par exemple

#define MAP_TYPE_CODE(Type, ID) \ 
template <> \ 
struct GetTypeCode<Type> \ 
{ \ 
    static const ParameterType Value = ID; \ 
}; 

MAP_TYPE_CODE(double, DOUBLE) 
MAP_TYPE_CODE(unsigned, UINT) 
2

Une approche différente de celle donnée par Marcelo Cantos créerions un métafonction:

template <typename T> 
struct my_type_id; // undefined as to trigger compiler error for unknown types 
template <> 
struct my_type_id<double> { 
    static const ParameterType value = DOUBLE; 
}; 
template <> 
struct my_type_id<float> { 
    static const ParameterType value = float; 
}; 

Et puis en utilisant que pour résoudre la valeur dénombrée:

template<class T> 
void SomeBuffer::append(T par) 
{  
    appendType(my_type_id<T>::value); 
    memcpy(pStr + _length, &par, sizeof(T)); 
    _length += sizeof(T); 
    appendType(my_type_id<T>::value); 
} 

La définition réelle de les traits peuvent être définis dans une macro:

#define TYPE_ID_MAP(type, val) \ 
    template <> struct my_type_id<type> { \ 
     const static ParameterType value = val;\ 
    } 
template <typename T> 
struct my_type_id; // undefined as to trigger compiler error for unknown types 
TYPE_ID_MAP(double, DOUBLE); 
TYPE_ID_MAP(float, FLOAT); 
TYPE_ID_MAP(unsigned int, UINT);