2012-10-26 11 views
8

Data una dichiarazione di classeÈ possibile utilizzare std :: enable_if per selezionare una specializzazione del modello membro?

class A { 
    template <typename T> T foo(); 
}; 

vorrei specializzarmi A::foo di vari tipi (int, ...) e le classi di tipo (POD, non-POD) di T. Sfortunatamente, non riesco a usare lo std::enable_if per quest'ultimo. Quanto segue non può essere compilato:

template <> int A::foo<int>(); // OK 

template <typename T> 
typename std::enable_if<is_pod<T>::value, T>::type foo(); // <<<< NOT OK! 

template <typename T> 
typename std::enable_if<!is_pod<T>::value, T>::type foo(); // <<<< NOT OK! 

Il problema è probabilmente dovuto al far parte std::enable_if<...> roba della firma funzione e che non ha dichiarato tali membri all'interno A. Quindi, come posso specializzare un membro del modello in base ai tratti del tipo?

risposta

4

non vedo alcuna ragione per specializzarsi qui, sovraccaricare la funzione sembra sufficiente nella mia mente.

struct A 
{ 
    template <typename T> 
    typename std::enable_if<std::is_integral<T>::value, T>::type foo() 
    { 
     std::cout << "integral" << std::endl; 
     return T(); 
    } 

    template <typename T> 
    typename std::enable_if<!std::is_integral<T>::value, T>::type foo() 
    { 
     std::cout << "not integral" << std::endl; 
     return T(); 
    } 
} 

Durante il controllo per POD o no POD, avete solo queste due scelte, in modo da una funzione più generica non è necessario (e non ha permesso, perché sarebbe ambiguo). Hai bisogno di più? È possibile verificare i tipi espliciti senza specializzazione con l'aiuto di std::enable_if<std::is_same<int, T>::value, T>::type.

+0

Ma non è possibile sovraccaricare solo sul tipo restituito ... –

+0

@Daniel Gehriger 'enable_if' è stato creato per la rimozione condizionale delle funzioni dalle risoluzioni di sovraccarico, quindi praticamente per questo caso. – nijansen

+0

Sì, ma ho ancora 'A :: foo ()' (e molte altre specializzazioni per alcuni tipi specifici) che entreranno in conflitto con qualsiasi cosa sia stata selezionata da 'enable_if'. –

4

che avevo appena avanti questo ad una struttura, che non gestisce bene:

#include <type_traits> 
#include <iostream> 

template <typename T, typename = void> 
struct FooCaller; 

class A { 
public: 
    template <typename T> 
    T foo() { 
     // Forward the call to a structure, let the structure choose 
     // the specialization. 
     return FooCaller<T>::call(*this); 
    } 
}; 

// Specialize for PODs. 
template <typename T> 
struct FooCaller<T, typename std::enable_if<std::is_pod<T>::value>::type> { 
    static T call(A& self) { 
     std::cout << "pod." << std::endl; 
     return T(); 
    } 
}; 

// Specialize for non-PODs.  
template <typename T> 
struct FooCaller<T, typename std::enable_if<!std::is_pod<T>::value>::type> { 
    static T call(A& self) { 
     std::cout << "non-pod." << std::endl; 
     return T(); 
    } 
}; 

// Specialize for 'int'. 
template <> 
struct FooCaller<int> { 
    static int call(A& self) { 
     std::cout << "int." << std::endl; 
     return 0; 
    } 
}; 
+3

Utilizzare 'std :: enable_if' qui è un po 'rotonda. Se il modello principale ammette 'typename = std :: true_type' come parametro predefinito, ad es. 'typename std :: is_pod :: type' è un modo più breve per ottenere la stessa specializzazione parziale. –

+0

Non male, ma ho bisogno di accedere ai dati di un membro da FooCaller, quindi dovrei inoltrare nuovamente la chiamata a una funzione membro di A. Che inizia a sembrare molto complicata. –

+0

Bene, basta un semplice 'template usando not_ = std :: integral_constant ;'. Oppure rendi una 'struct' per i compilatori che non supportano ancora l'utilizzo di alias:' modello struct not_: std :: integral_constant {}; 'e lo usa nelle specifiche parziali:' FooCaller > :: type> ' – Xeo

Problemi correlati