Come posso estendere un cast lessicale per supportare i tipi enumerati?

Ho la seguente funzione che convertirà una stringa in un tipo di dati numerico:

template  bool ConvertString(const std::string& theString, T& theResult) { std::istringstream iss(theString); return !(iss >> theResult).fail(); } 

Questo non funziona per i tipi enumerati, tuttavia, quindi ho fatto qualcosa di simile:

 template  bool ConvertStringToEnum(const std::string& theString, T& theResult) { std::istringstream iss(theString); unsigned int temp; const bool isValid = !(iss >> temp).fail(); theResult = static_cast(temp); return isValid; } 

(Sto facendo l’ipotesi che theString abbia un valore valido per il tipo enumerato, lo sto usando principalmente per la serializzazione semplice)

C’è un modo per creare un’unica funzione che combini entrambi?

Ho giocato un po ‘con gli argomenti del modello ma non ho trovato nulla; sarebbe bello non dover chiamare una funzione per i tipi enumerati e un’altra per tutto il resto.

Grazie

Devi fare due passaggi. Trovare un tipo integrale abbastanza grande da memorizzare i valori. Potresti usare unsigned long , ma i valori potrebbero essere negativi. Quindi è ansible utilizzare a long ma i valori potrebbero estendersi nell’intervallo di unsigned long . Quindi non esiste un tipo adatto a tutti.

C’è un trucco però, usando la risoluzione di sovraccarico. Eccolo

 template struct id { typedef T type; }; id::type &find_etype(int); id::type &find_etype(unsigned int); id::type &find_etype(long); id::type &find_etype(unsigned long); 

Puoi cambiarlo in modo appropriato per coprire anche long long o unsigned long long se la tua implementazione ha il supporto per questo. Ora, il passaggio di un tipo di enumerazione preferirà uno di questi a tutti gli altri – questo è un tipo che può memorizzare tutti i valori di esso. Hai solo bisogno di passare sizeof del tipo di ritorno ad un template.

 template struct get_etype; template<> struct get_etype<1> { typedef int type; }; template<> struct get_etype<2> { typedef unsigned int type; }; template<> struct get_etype<3> { typedef long type; }; template<> struct get_etype<4> { typedef unsigned long type; }; 

Ora puoi ottenere un tipo giusto. Tutto ciò che serve ora è vedere se un certo tipo è un’enumerazione. Come fare questo è descritto nel libro “Modelli C ++ – La guida completa”, e sfortunatamente è un sacco di codice. Quindi vorrei usare is_enum di is_enum . Mettendolo insieme, potrebbe sembrare

 template  typename boost::disable_if< boost::is_enum, bool>::type ConvertString(const std::string& theString, T& theResult) { std::istringstream iss(theString); return !(iss >> theResult).fail(); } template  typename boost::enable_if< boost::is_enum, bool>::type ConvertString(const std::string& theString, T& theResult) { typedef typename get_etype::type safe_type; std::istringstream iss(theString); safe_type temp; const bool isValid = !(iss >> temp).fail(); theResult = static_cast(temp); return isValid; } 

Spero che questo ti aiuti.

E solo per “completare” la domanda, in C ++ 0x possiamo solo fare questo:

 typedef typename std::underlying_type::type safe_type; 

Al posto del trucco get_etype di Johannes.