2012-10-26 2 views
8

eine KlassendeklarationIst es möglich, std :: enable_if zu verwenden, um eine Mitgliedervorlagenspezialisierung auszuwählen?

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

Gegeben Ich mag würde A::foo für verschiedene Arten spezialisieren (int, ...) und Typklassen (POD, nicht-POD) von T. Leider kann ich std::enable_if nicht für letzteres verwenden. Die folgende lässt sich nicht kompilieren:

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! 

Die Frage an die std::enable_if<...> Sachen als Teil der Funktionssignatur wahrscheinlich ist, und dass ich nicht erklären, eine solche Mitglied innerhalb A. Wie kann ich ein Template-Mitglied basierend auf Typeigenschaften spezialisieren?

Antwort

4

Ich sehe keinen Grund, hier zu spezialisieren, Überlastung die Funktion in meinem Kopf zu genügen scheint.

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

Wenn für POD oder ohne POD Kontrolle, haben Sie nur diese zwei Möglichkeiten, so eine allgemeinere Funktion nicht benötigt wird (und nicht erlaubt, weil es eindeutig ist). Du brauchst mehr als das? Sie können mit Hilfe von std::enable_if<std::is_same<int, T>::value, T>::type nach expliziten Typen ohne Spezialisierung suchen.

+0

Aber Sie können nicht nur auf Rückgabetyp überladen ... –

+0

@Daniel Gehriger 'enable_if' wurde für bedingte Entfernen von Funktionen aus Überlast-Auflösungen gemacht, so ziemlich genau für diesen Fall. – nijansen

+0

Ja, aber ich habe immer noch die 'A :: foo ()' (und viele andere Spezialisierungen für einige spezifische Typen), die mit dem kollidieren, was von 'enable_if' ausgewählt wurde. –

4

Ich würde nur weiterleiten zu einer Struktur, die diese gut im Griff hat:

#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

Mit 'std :: enable_if' hier ist ein bisschen Kreisverkehr. Wenn die primäre Vorlage "typename = std :: true_type" als einen voreingestellten Parameter zulässt, dann z. 'typenname std :: is_pod :: type 'ist ein kürzerer Weg, um dieselbe partielle Spezialisierung zu erreichen. –

+0

Nicht schlecht - aber ich muss auf A-Mitgliedsdaten von FooCaller zugreifen, also müsste ich den Anruf noch einmal an eine Mitgliedsfunktion von A weiterleiten. Das sieht sehr kompliziert aus. –

+0

Nun, haben Sie einfach eine einfache 'Vorlage mit not_ = std :: integral_constant ;'. Oder machen Sie es zu einer 'struct' für Compiler, die noch keine Aliase unterstützen: 'template struct not_: std :: integral_constant {};' und verwenden Sie das in der partiellen Spezifikation: ' FooCaller >> type> ' – Xeo

Verwandte Themen