Un altro modo in cui ho visto questo tipo di cose fatte in alcune codebase è, fondamentalmente, usare un tratto di tipo per decorare le enumerazioni con scope con informazioni extra.
L'idea è che si avrebbe qualche tratto come
namespace mpl {
template <typename T>
struct GetEnumData;
}
Poi, quando si dichiara un'enum "intelligente", sarà anche specializzarsi questo tratto di collegarsi a una struttura che contiene metadati sul enum con ambito , come quello che sono i valori legali. Oppure, un elenco di stringhe corrispondenti ai nomi dei valori enum, in modo da poter eseguire la conversione enum-to-string e viceversa.
enum class my_enum { a, b, c };
namespace mpl {
template<>
struct GetEnumData<my_enum> {
static constexpr std::size_t my_number = 3;
static const char * const my_strings []() {
return {"a", "b", "c"};
}
static const int my_values []() {
return {0, 1, 2};
}
}
} // end namespace mpl
N.B. Generare il tipo di carattere sopra è un po 'noioso, quindi invariabilmente, si finisce per utilizzare alcune macro per le dichiarazioni "smart enum". Se davvero non ti piacciono le macro, questo approccio non fa per te. Almeno fino a quando C++ aggiunge alcune funzionalità di introspezione nelle versioni future (dita incrociate).
Una volta che si dispone di questo tipo di tratto, è possibile fare cose utili come "enum_cast" che analizzerà una stringa per un enum, per esempio.
template <typename T>
T enum_cast(const std::string & input) {
using data = GetEnumData<T>;
for (std::size_t idx = 0; idx < data::my_number; ++idx) {
if (data::my_strings()[idx] == input) {
return static_cast<T>(data::my_values()[idx]);
}
}
throw bad_enum_value(input);
}
E si potrebbe fare qualcosa di simile per int
's o altri tipi integrali.
Il comportamento non è indefinito. Sezione 7.2, paragrafo 10 dice "Un'espressione di tipo aritmetico o di enumerazione può essere convertita esplicitamente in un tipo di enumerazione, il valore è invariato se si trova nell'intervallo dei valori di enumerazione del tipo di enumerazione; altrimenti il valore di enumerazione risultante non è specificato ** ". Quindi il valore non è specificato, ma il comportamento non è indefinito (nessun demone nasale). – Cornstalks
@Cornstalks, grazie per avermelo fatto notare. Questo è decisamente meglio di quanto non sia definito. Tuttavia, la domanda è la seguente: c'è un modo carino per scoprire se il valore non è valido? – toth
Purtroppo non ne sono a conoscenza. – Cornstalks