2012-12-20 4 views
23

Warum kompiliert dies nicht mit gcc48 und clang32?Warum kompilieren Fehler mit 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 Fehler:

/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 Fehler:

/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 - LÖSUNG

ich Antwort von Charles Salvia, aber aus praktischen Gründen nicht angenommen habe ich konnte die vorgeschlagene Problemumgehung (spezialisiert auf N) nicht verwenden. Ich habe eine andere Problemumgehung gefunden, die für mich funktioniert. Machen enable_if hängen von T:

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

Sind Sie sicher, dass dies sowieso funktionieren wird? Sie können Methoden nicht einfach über ihren Rückgabetyp überladen (es sei denn, 'enable_if' ist als Sprachkonstrukt implementiert und nicht, wie ich derzeit annahm, eine einfache Template-Klasse). – zneak

+0

Warum ist die Problemumgehung, enable_if von T abhängig zu machen, genau notwendig? –

+0

Die Lösung funktioniert nicht für mich! Ich habe 'Fehler: keine passende Funktion für Anruf ...' –

Antwort

14

Weil Sie enable_if ohne Verwendung der Template-Parameter T in Ihrer Funktion Vorlagen verwenden. Wenn Sie sich spezialisieren möchten, wenn die Struktur S einen bestimmten Vorlagenparameterwert N hat, müssen Sie die Klassenvorlagenspezialisierung verwenden.

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

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

std::enable_if Um so zu arbeiten, Sie auf SFINAE setzen. Leider an dem Punkt, wo Sie erklären

S<1> s1; 

es werden alle S<1> ‚Mitglieds Erklärungen instanziiert. SFINAE kommt erst dann zum Tragen, wenn ein schlecht ausgebildetes Konstrukt ist. Es ist nicht. Leider enthält es eine Funktion, die ungültig ist, daher ist die Instanziierung S<> ungültig.

Für Dinge wie diese, könnte ich auf eine separate Vorlage Struktur verschieben:

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

[Diese Frage] (http: // stackoverflow.com/questions/6972368/stdenable-wenn-zu-bedingt-kompilieren-ein-Mitglied-Funktion) hat einige weitere Informationen. – Anthony

1

Für diesen Fall, dass Sie überhaupt über nicht mit enable_if denken konnte. Es ist posible einfach zu spezialisieren 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

eine Standard boolean Template-Parameter verwenden, wie folgt aus:

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

Nun, ich bin nicht sicher, was Sie tun wollen, aber vielleicht wird dieser Code helfen :

#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); 
} 

Dies druckt 1 und 2.