2010-11-11 10 views
11

in codice:Come utilizzare enable_if per abilitare le funzioni di membro sulla base di parametro di modello di classe

template<class T> 
struct is_builtin 
{ 
    enum {value = 0}; 
}; 

template<> 
struct is_builtin<char> 
{ 
    enum {value = 1}; 
}; 

template<> 
struct is_builtin<int> 
{ 
    enum {value = 1}; 
}; 

template<> 
struct is_builtin<double> 
{ 
    enum {value = 1}; 
}; 

template<class T> 
struct My 
{ 
    typename enable_if<is_builtin<T>::value,void>::type f(T arg) 
    { 
     std::cout << "Built-in as a param.\n"; 
    } 


    typename enable_if<!is_builtin<T>::value,void>::type f(T arg) 
    { 
     std::cout << "Non - built-in as a param.\n"; 
    } 
}; 

struct A 
{ 
}; 

int main() 
{ 
    A a; 
    My<int> m; 
    My<A> ma; 
    m.f(1); 
    ma.f(a); 
    return 0; 
} 

sto ottenendo un errore:

error C2039: 'type' : is not a member of 'std::tr1::enable_if<_Test,_Type>'  

Ovviamente non capisco come utilizzare enable_if. Quello che stavo pensando è che posso abilitare una o la seconda funzione membro da un insieme di funzioni membro durante il tempo di compilazione, ma non funziona. Qualcuno potrebbe spiegarmi come farlo correttamente?
Modificato
Quello che davvero non riesco a capire è perché non ci sia typedef in uno di quelli def. Il compilatore non riesce a trovarlo e non lo compila.

risposta

13

Non è possibile utilizzare i parametri del modello di classe per ottenere SFINAE per le funzioni membro.

Si sia bisogno di

  • rendere la funzione di membro di un modello di funzione membro invece e utilizzare enable_if sui parametri di modello del modello di funzione di membro o

  • mossa la funzione di membro f in una classe politica e di specializza il modello di classe usando enable_if.

+0

potrebbe fornire qualche esempio per favore? –

+0

@C'è un esempio di utilizzo del secondo approccio (specializzazione di un modello di classe) in [la documentazione Boost 'enable_if'] (http://beta.boost.org/doc/libs/1_44_0/libs/utility/enable_if .html) (vedere la sezione 3.1). –

+0

grazie per il collegamento. Andando a leggerlo ora. –

-2

enable_if prevede una metafunzione. Per usare un bool è necessario enable_if_c. Sono sorpreso che non stai ricevendo errori che spiegano quel problema.

È possibile correggere la metafunzione dichiarando un typedef 'tipo' all'interno che è semplicemente se stesso. Quindi è possibile utilizzare boost::enable_if<is_builtin<T>>::type

+1

Io uso std :: enable_if –

0

Ecco come funziona (si noti che per comodità ho sostituito il vostro is_builtin tratto con std::is_arithmetic e usato ulteriormente C++ 11 roba, ma funziona in qualsiasi modo):

template<class T> 
struct My 
{ 
    template<typename T_ = T, std::enable_if_t<std::is_arithmetic<T_>::value>* = nullptr> 
    void f(T_ arg) 
    { 
     std::cout << "Built-in as a param.\n"; 
    } 

    template<typename T_ = T, std::enable_if_t<!std::is_arithmetic<T_>::value>* = nullptr> 
    void f(T_ arg) 
    { 
     std::cout << "Non - built-in as a param.\n"; 
    } 
}; 

DEMO

la parte cruciale è quello di portare il parametro di modello nel contesto immediato utilizzando una funzione predefinita parametro di template T_ che è uguale al parametro modello di classe T. Per maggiori dettagli, vedi this question.

1

È possibile correggere il codice utilizzando modificati enable_if

template < typename T > 
struct __Conflict {}; 

template <bool B, class T = void> 
struct __enable_if { typedef __Conflict<T> type; }; 

template <class T> 
struct __enable_if<true, T> { typedef T type; }; 

Esempio di utilizzo:

template <typename T> 
class Lazy 
{ 
public: 
    void _ctor(bool b); 
    void _ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type); 
}; 

template <typename T> 
void Lazy<T>::_ctor(bool b) 
{ 
    std::cout << "bool " << b << std::endl; 
}; 

template <typename T> 
void Lazy<T>::_ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type t) 
{ 
    std::cout << "T " << t << std::endl; 
}; 

int main(int argc, char **argv) 
{ 
    Lazy<int> i; 
    i._ctor(10); 
    i._ctor(true); 

    Lazy<bool> b; 
    b._ctor(true); 

    return 0; 
} 
+0

+1, anche se di solito cerco di evitare di iniziare i nomi con caratteri di sottolineatura perché ci sono regole in cui ogni nome che inizia con uno o due caratteri di sottolineatura sono riservati in alcuni casi. Inoltre, c'è un motivo per cui hai chiamato una funzione '_ctor' invece di limitarti a definire un costruttore? – SirGuy

+0

poiché ricordo che i caratteri di sottolineatura sono usati per mostrare l'implementazione locale di qualcosa, _ctor è solo il nome del metodo nel mio codice che non mi preoccupai di rinominare – Alexander77

+0

da [cppreference] (http://en.cppreference.com/w/ cpp/parola chiave): _Also, ** tutti gli identificatori che contengono un doppio carattere di sottolineatura __ in qualsiasi posizione ** e ogni identificatore che inizia con un trattino basso seguito da una lettera maiuscola è sempre riservato e tutti gli identificatori che iniziano con un trattino basso sono riservati per utilizzare come nomi nello spazio dei nomi globale. Vedere gli identificatori per ulteriori dettagli._ Quindi, per lo meno il modello '__enable_if' dovrebbe essere rinominato per assicurarsi che non interferisca mai con i dettagli di implementazione della libreria standard. – SirGuy

Problemi correlati