2013-06-15 6 views
10

Ich habe vor einer Woche eine Frage gestellt, in der ich gefragt wurde, wie ich eine Klassenvorlage nur dann instanziieren könnte, wenn der Typ, den sie benötigt, eine bestimmte Elementfunktion hätte. In meiner Antwort bekam ich eine Art komplizierte Lösung. Aber dann habe ich versucht, es alleine zu machen. Ich wollte nur wissen, ob dies genug, um aus einem gegebenen Typ T hat eine void-Funktion namens f unter 0 Parameter.Wird dies als SFINAE betrachtet?

#include <type_traits> 
#include <utility> 

template <typename T, typename = void> 
struct has_f : std::false_type { }; 

template <typename T> 
struct has_f< 
    T, 
    decltype(std::declval<T>().f(), void())> : std::true_type { }; 

template <typename T, typename = typename std::enable_if<has_f<T>::value>::type> 
struct A { }; 

struct B 
{ 
    void f(); 
}; 

struct C { }; 

template class A<B>; // compiles 
template class A<C>; // error: no type named ‘type’ 
        // in ‘struct std::enable_if<false, void>’ 

Wenn ja, warum die anderen Antworten sind so kompliziert in this thread?

+2

Ja verwenden, ist dies SFINAE und ja, das ist richtig. Warum sind die anderen Antworten komplizierter? Schwer zu sagen. –

+0

Um zu verdeutlichen, dass "has_f" sich auf SFINAE stützt, tut 'A' das nicht. –

+0

Als eine Möglichkeit, SFINAE Unterstützung in einigen Compilern (* hust * MSVC2012) Art von saugt, so könnte ein Teil dieser Komplexität Workarounds sein, um eine tragbare SFINAE haben. Nebenbei, 'std :: declval () .f()' und 'std :: declval () .f()' (oder ist es 'std :: declval () .f()'?) kann in C++ 1y aufgrund des rvalue-Verweises auf dieses Merkmal anders sein. – Yakk

Antwort

7

Yep, haben Sie es in der einfachsten, idiomatischen Stil von C++ 11 SFINAE gelöst.

Beachten Sie, dass Sie nicht überprüft haben, ob der Rückgabetyp void ist, dass es sich um ein nicht statisches Element handelt oder dass es keine Parameter gibt. f ist einfach ohne Argumente aufrufbar. Es könnte sogar ein Funktor sein.

Um zu überprüfen, für eine nullary nicht-statische Funktion Mitglied void Rückkehr

template <typename T> 
struct has_f<T, decltype(void(static_cast< void (T::*)(void) >(&T::f))) > 
    : std::true_type {}; 

template <typename T> 
struct has_f<T, decltype(void(static_cast< void (T::*)(void) const >(&T::f))) > 
    : std::true_type {}; 
+0

Also verwende ich 'std :: result_of', um zu überprüfen, ob der Rückgabetyp ungültig ist? –

+0

@MemyselfandI Das ist eine Möglichkeit, Sie könnten auch 'declltype' verwenden. 'std :: result_of' macht einen seltsamen Tanz, um das INVOKE-Konzept von' std :: bind' und 'std :: function' zu unterstützen. Siehe meine Bearbeitung für eine schnelle Möglichkeit, mehrere Bedingungen gleichzeitig zu überprüfen. In jedem Fall brauchen Sie auch 'std :: is_same'. – Potatoswatter

+0

Ich glaube, du meintest 'std :: is_same :: value' (verschobene schließende Klammer) und ähnlich für die Zeile darunter. – hvd