2013-03-23 10 views
13

Sto scrivendo un alias modello di promozione simile a boost :: promote ma per C++ 11. Lo scopo di questo è evitare avvisi quando si recuperano argomenti da funzioni varidiche. per esempio.C++ 11 tipo tratto per distinguere tra classe enum e normale enum

template <typename T> 
std::vector<T> MakeArgVectorV(int aArgCount, va_list aArgList) 
{ 
    std::vector<T> args; 
    while (aArgCount > 0) 
    { 
     args.push_back(static_cast<T>(va_arg(aArgList, Promote<T>))); 
     --aArgCount; 
    } 
    return args; 
} 

Il Promuovere modello alias promuove il tipo di seguito la promozione argomento di default per gli argomenti variadic: 1) Un numero intero che è più piccolo di un int è promosso a int 2) Un galleggiante è promosso a raddoppiare

Il mio problema è che è possibile promuovere un enumerazione C++ standard ma una classe enum C++ 11 non viene promossa (il compilatore non genera un avviso). Voglio Promuovere di lavorare con una normale enum ma ignorare una classe enum di C++ 11.

Come posso distinguere tra una classe di enumerazione e un'enumerazione nel mio alias di modello Promuovi?

+1

Il vero problema è che stai usando 'va_arg's invece di una' std :: initializer_list' e/o modelli variadic. – Fanael

+0

Grazie per il suggerimento, ma ho la va_list perché sto lavorando con un'interfaccia C. – Sam

+0

@ Sam: la mia risposta è stata risolta? –

risposta

21

Ecco una possibile soluzione:

#include <type_traits> 

template<typename E> 
using is_scoped_enum = std::integral_constant< 
    bool, 
    std::is_enum<E>::value && !std::is_convertible<E, int>::value>; 

La soluzione sfrutta la differenza di comportamento tra scope e enumerazioni senza ambito specificato nel paragrafo 7.2/9 della C++ 11 standard:

L' il valore di un enumeratore o di un oggetto di un tipo di enumerazione senza ambito viene convertito in un intero dalla promozione integrale (4.5). [...] Si noti che questo enum implicito per la conversione int non è fornito per l'enumerazione dell'ambito. [...]

Ecco una dimostrazione di come si dovrebbe utilizzare:

Ed ecco un live example.

RINGRAZIAMENTI:

Grazie a Daniel Frey per aver ricordato che il mio approccio precedente avrebbe funzionato solo fino a quando non v'è un sovraccarico definita dall'utente di operator +.

+3

+1, ma c'è una caverna: funziona solo se l'autore di qualche enum classe 'E' ha ** non ** definito il proprio' operatore + (int, E) '. Risolvilo aggiungendo un 'void dummy (int)' e usa 'decltype (dummy (std :: declval ()))'. –

+1

@DanielFrey: buon punto. In realtà, potrei usare un operatore diverso, come '^', per rendere meno probabile l'interferenza con un sovraccarico dell'operatore definito dall'utente –

+1

@AndyProwl: o chiamare una funzione che accetta un 'int'. – Fanael