2012-08-17 5 views
6

Ich habe folgenden Code, der nicht kompiliert. Dies sind zwei Funktionen in einer Template-Klasse, die die ArgumenteTemplate-Methode enable_if Spezialisierung

typename std::enable_if<std::is_void<Ret>::value, Ret>::type _on_dispatched() { 
    // ... 
} 

typename std::enable_if<!std::is_void<Ret>::value, Ret>::type _on_dispatched() { 
    // .... 
} 

ich eine Spezialisierung haben will in einer Element-Methode nimmt je nachdem, welche Art Ret ist.

Hat jemand eine Idee?

Antwort

7

SFINAE funktioniert nicht bei Nicht-Template-Funktionen (Mitglied oder Nicht-Mitglied).

Wie Kerrek SB darauf hinweist, funktioniert das Erstellen von Nichtmitgliedsfunktionsvorlagen. Oder Xeo weist darauf hin, dass es auch funktioniert, wenn man sie zu Member-Funktions-Templates mit einem voreingestellten Template-Argument macht.

Dies funktioniert jedoch nur, weil die beiden std::enable_if Bedingungen nicht überlappende sind. Wenn Sie eine andere Überladung für int (sagen wir) hinzufügen möchten, dann werden Sie feststellen, dass es nicht so gut skaliert. Je nachdem, was Sie tun möchten, Tag Dispatching skaliert der Regel besser als SFINAE mit mehreren Alternativen, die Sie versenden am möchten:

#include<type_traits> 

template<typename Ret> 
class Foo 
{ 
public: 
    void _on_dispatched() 
    { 
     // tag dispachting: create dummy of either std::false_type or std::true_type 
     // almost guaranteed to be optimized away by a decent compiler 
     helper_on_dispatched(std::is_void<Ret>()); 
    } 

private: 
    void helper_on_dispatched(std::false_type) 
    { 
     // do stuff for non-void 
    } 

    void helper_on_dispatched(std::true_type) 
    { 
     // do stuff for void 
    } 
}; 

int main() 
{ 
    Foo<void>()._on_dispatched(); 
    Foo<int>()._on_dispatched(); 
    return 0; 
} 
+1

Sie können, wenn einer der Überlastung ist die einzig denkbare bei Gesprächszeit. :) http://liveworkspace.org/code/fd6e5383610d4e0d8fb17c5497991355 – Xeo

+1

@Potatoswatter: Eigentlich, nein, es war kein Witz. Wenn Sie den Link sehen, können Sie eine Funktion mit genau der gleichen Signatur verwenden, bei der nur der Rückgabetyp entscheidet, ob er funktionsfähig ist. : P Auch verwenden Sie einfach 'std :: is_void ()', Typ Traits müssen entweder von 'std :: true_type' oder' std :: false_type' abgeleitet werden. – Xeo

+1

Btw, [Sie können nur die Member-Funktion eine Vorlage mit einem voreingestellten Parameter in C++ 11 machen] (http://liveworkspace.org/code/781d94df5499998947217970c1aebf2a). – Xeo

3

SFINAE funktioniert nur auf Vorlagen. Ihr Code kann gemacht werden, mit einer kleinen Modifikation zu kompilieren:

template <typename Ret> 
typename std::enable_if<std::is_void<Ret>::value, Ret>::type _on_dispatched() { /*...*/ } 

template <typename Ret> 
typename std::enable_if<!std::is_void<Ret>::value, Ret>::type _on_dispatched() { /*...*/ } 

Verbrauch:

auto q = _on_dispatched<int>(); 

Sie können natürlich nicht den Rückgabetyp einer Funktion ableiten, da es nicht ableitbar ist. Allerdings können Sie diese Vorlage packen innen eine andere Vorlage:

template <typename T> 
struct Foo 
{ 
    // insert templates here, maybe privately so 

    T bar() { return _on_dispatched<T>(); } 
}; 
+0

'Vorlage ' für die Mitgliederfunktionen, siehe meinen Kommentar zu Rhalbersma's Antwort. – Xeo

+0

@Xeo: Sie meinen, das würde uns davor bewahren, '' schreiben zu müssen? Sicher warum nicht :-) –