2015-09-08 13 views
7

Ho una funzione template in cui un tipo enum viene convertito nel suo tipo sottostante che funziona bene, ma ho scritto un overload che dovrebbe prendere un numero intero e restituire se stesso e dare un errore che int non è un tipo di enumerazione. Nel mio modello, questo dovrebbe essere stato filtrato. Che c'è?"Conversion" dal tipo allo stesso tipo sta causando l'errore

Ecco il codice del modello:

template <typename TT> 
    static constexpr auto get_value(TT t) 
    -> typename std::enable_if<!std::is_enum<TT>::value, TT>::type 
    { 
     return t; 
    } 

    template <typename TT> 
    static constexpr auto get_value(TT t) 
    -> typename std::enable_if<std::is_enum<TT>::value, typename std::underlying_type<TT>::type>::type 
    { 
     return (typename std::underlying_type<TT>::type)t; 
    } 

Demo

+1

Non so se 'underlying_type' è SFINAE-friendly, ma c'è una [soluzione] (http://coliru.stacked-crooked.com/a/e7f1dd3b75c8d9c2) per quel –

+0

Cosa? Vedo che funziona, ma cosa sta succedendo qui che lo fa funzionare? E perché non dovrebbe il 'underlying_type' di SFINAE essere amichevole? – Adrian

+1

L'istanziazione di 'std :: underlying_type :: type' è posticipata, in modo che' enable_if' possa fallire per primo. Con * SFINAE-friendly * Intendo dire che ogni errore di sostituzione avviene solo nel contesto immediato (se accade all'interno di 'underlying_type' stesso non è compatibile con SFINAE). –

risposta

4

std::underlying_type<TT>::type è stato valutato in std::enable_if anche se std::is_enum<TT>::value è false come false non è un errore. Poiché un tipo di enumerazione non è in fase di valutazione, sta causando un errore. Se spostiamo la SFINAE nei parametri del modello, possiamo ottenere i sovraccarichi desiderati e restituire ancora il tipo corretto.

template <typename TT, typename std::enable_if<!std::is_enum<TT>::value, TT>::type* = nullptr> 
static constexpr auto get_value(TT t) -> TT 
{ 
    return t; 
} 

template <typename TT, typename std::enable_if<std::is_enum<TT>::value>::type* = nullptr> 
static constexpr auto get_value(TT t) -> typename std::underlying_type<TT>::type 
{ 
    return (typename std::underlying_type<TT>::type)t; 
} 

Si può vedere che funziona in questo Live Example

+0

Quindi, per essere sicuro di capirlo correttamente, il parametro 2nd template è un parametro senza nome di tipo 'void *' se è/non è enum type (a seconda di cosa voglio) risultante nella creazione e non entità se non è quello che voglio e sarebbe quindi respinto? – Adrian

+0

@Adrian Se 'std :: enable_if' ha successo' type' è vuoto e possiamo quindi impostare un puntatore di tipo su 'nullptr' per SFINAE – NathanOliver

+0

@dyp Ho modificato la risposta. Dovrebbe indirizzare la causa attuale ora. – NathanOliver

4

Tentando di istanziare std::underlying_type<T> con T che non è un tipo enum, si stanno violando un requisito che la norma impone parametro di template T:

§ 20.10.7.6 [meta.trans.other]/Tabella 57:

 Template   |   Condition   |  Comments 
------------------------+---------------------------+----------------------- 
template <class T>  | T shall be an enumeration | The member typedef 
struct underlying_type; | type (7.2)    | type shall name 
         |       | the underlying type 
         |       | of T. 

Ecco un approccio alternativo, se uno non piace alcun parametro di template aggiuntivi:

template <typename TT> 
static constexpr auto get_value(TT t) 
    -> typename std::enable_if<!std::is_enum<TT>::value, TT>::type 
{ 
    return t; 
} 

template <typename TT> 
static constexpr auto get_value(TT t) 
    -> typename std::enable_if<std::is_enum<TT>::value 
          , std::underlying_type<TT> 
       >::type::type 
{ 
    return (typename std::underlying_type<TT>::type)t; 
} 

In questo modo, l'istanza di std::underlying_type<TT> è differito fino alla condizione in std::enable_if restituisce true, perché viene richiesto un nidificato type definizione per quali resi std::enable_if<B,T>::type.

DEMO

+0

Quindi, il requisito è necessario solo se si ottiene il tipo 'std :: underlying_type :: type' ma non necessario per' std :: underlying_type 'stesso? Perché? – Adrian

+1

@Adrian 'std :: underlying_type ' non viene istanziato quando viene utilizzato solo come argomento modello tipo –

Problemi correlati