2012-12-20 10 views
23

Perché questo non viene compilato con gcc48 e clang32? Errore diPerché compile errore con enable_if

#include <type_traits> 

template <int N> 
struct S { 

    template<class T> 
    typename std::enable_if<N==1, int>::type 
    f(T t) {return 1;}; 

    template<class T> 
    typename std::enable_if<N!=1, int>::type 
    f(T t) {return 2;}; 
}; 

int main() { 
    S<1> s1; 
    return s1.f(99); 
} 

GCC: errore

/home/lvv/p/sto/test/t.cc:12:2: error: no type named ‘type’ in ‘struct enable_if<false, int>’ 
    f(T t) {return 2;}; 
^

CLANG:

/home/lvv/p/sto/test/t.cc:11:26: error: no type named 'type' in 'std::enable_if<false, int>'; 'enable_if' cannot be used to 
     disable this declaration 
     typename std::enable_if<N!=1, int>::type 
           ^~~~ 
/home/lvv/p/sto/test/t.cc:16:7: note: in instantiation of template class 'S<1>' requested here 
     S<1> s1; 
      ^

EDIT - SOLUZIONE

Ho accettato risposta da Charles Salvia, ma per motivi pratici I non è stato in grado di utilizzare la soluzione proposta (specializzarsi su N). Ho trovato altri rimedi che funzionano per me. Fai enable_if dipendono T:

typename std::enable_if<(sizeof(T),N==1), int>::type 
+1

Sei sicuro che questo sta andando a lavorare in ogni modo? Non è possibile sovraccaricare i metodi solo con il loro tipo di ritorno (a meno che 'enable_if' non sia implementato come un costrutto del linguaggio piuttosto che, come sto assumendo, una semplice classe basata su modelli). – zneak

+0

Perché la soluzione alternativa per rendere enable_if dipende da T necessario, esattamente? –

+0

La soluzione non funziona per me! Ho ottenuto 'errore: nessuna funzione di abbinamento per la chiamata ...' –

risposta

14

Perché si utilizza enable_if senza utilizzare il parametro di template T nei modelli di funzione. Se si desidera specializzarsi per quando la struttura S ha un determinato valore del parametro modello N, sarà necessario utilizzare la specializzazione del modello di classe.

template <int N, class Enable = void> 
struct S { }; 

template <int N> 
struct S<N, typename std::enable_if<N == 1>::type> 
{ 
    .... 
}; 
5

Per arrivare std::enable_if a lavorare in questo modo, si fa affidamento su SFINAE. Purtroppo, nel punto in cui si dichiara

S<1> s1; 

che verrà un'istanza di tutte le dichiarazioni dei membri S<1> s'. SFINAE entrerà in gioco solo a questo punto se lo S<1> fosse un costrutto malformato. Non è. Sfortunatamente, contiene una funzione che non è valida, quindi l'istanziazione di S<> non è valida.

per cose come questa, mi permetto di rinviare a un modello struct separato:

template <bool B> 
struct f_functor { 
    template <typename T> 
    static int f(T t) { return 1; } 
}; 

template <> 
struct f_functor<false> { 
    template <typename T> 
    static int f(T t) { return 2; } 
}; 

template <int N> 
struct S { 

    template<class T> 
    typename int f(T t) { return f_functor<N==1>::f(t); } 
}; 
+1

[Questa domanda] (http: // StackOverflow.it/questions/6972368/stdenable-if-to-conditionally-compile-a-member-function) ha qualche informazione in più. – Anthony

1

Per questo caso si potrebbe pensare di non usare enable_if affatto. È posible di specializzarsi semplicemente f:

template <int N> 
struct S { 
    template<class T> int f(T t); 
}; 

template<int N> 
template<class T> 
int S<N>::f(T t) { return 2; } 

template<> 
template<class T> 
int S<1>::f(T t) { return 1; } 

int main() { 
    S<1> s1; 
    return s1.f(99); 
} 
6

utilizzare un parametro modello predefinito booleano, in questo modo:

template <int N> 
struct S { 

    template<class T, bool EnableBool=true> 
    typename std::enable_if<N==1 && EnableBool, int>::type 
    f(T t) {return 1;}; 

    template<class T, bool EnableBool=true> 
    typename std::enable_if<N!=1 && EnableBool, int>::type 
    f(T t) {return 2;}; 
}; 
7

Beh, io non sono sicuro di quello che si voleva fare, ma forse questo codice aiuterà :

#include <iostream> 

template <int N> 
struct S { 

    template<class T=int> 
    typename std::enable_if<N==1, T>::type 
    f(T t) {return 1;} 

    template<class T=int> 
    typename std::enable_if<N!=1, T>::type 
    f(T t) {return 2;} 
}; 

int main() 
{ 
    S<1> s1; 
    S<2> s2; 
    std::cout << s1.f(99) << " " << std::endl << s2.f(5); 
} 

questo stampa 1 e 2.