2010-01-24 8 views
10

Ich habe gerade herausgefunden, wie überprüft werden kann, ob operator<< für einen Typ zur Verfügung gestellt wird.SFINAE + sizeof = erkennen, ob Ausdruck kompiliert

template<class T> T& lvalue_of_type(); 
template<class T> T rvalue_of_type(); 

template<class T> 
struct is_printable 
{ 
    template<class U> static char test(char(*)[sizeof(
     lvalue_of_type<std::ostream>() << rvalue_of_type<U>() 
    )]); 
    template<class U> static long test(...); 

    enum { value = 1 == sizeof test<T>(0) }; 
    typedef boost::integral_constant<bool, value> type; 
}; 

Ist dieser Trick bekannt, oder habe ich gerade den Metaprogrammierungs-Nobelpreis gewonnen? ;)

EDIT: Ich machte den Code einfacher zu verstehen und einfacher mit zwei globalen Funktionsschablonen Deklarationen lvalue_of_type und rvalue_of_type anzupassen.

+0

Mit VC++ scheint 'is_printable :: value' für jedes X wahr und mit Comeau Online scheint es falsch für jedes X. – UncleBens

+0

Mit g ++, bekomme ich 1 für' is_printable :: value' und 0 für 'is_printable > :: value', also funktioniert es gut für mich. – fredoverflow

+4

So funktioniert es auf 1 von 3 Compilern ... – UncleBens

Antwort

5

Es ist eine gut bekannte Technik, ich :-)

Angst habe

Die Verwendung eines Funktionsaufruf in dem sizeof Bediener den Compiler anweist Argumente Abzug und Funktionsanpassung durchzuführen, zur Kompilierzeit natürlich. Mit einer Template-Funktion instanziiert der Compiler auch eine konkrete Funktion aus einer Vorlage. Dieser Ausdruck bewirkt jedoch nicht, dass ein Funktionsaufruf generiert wird. Es ist gut beschrieben in SFINAE Sono Buoni PDF.

Überprüfen Sie andere C++ SFINAE examples.

1

Es ist nur eine Kombination aus zwei bekannten Tricks. SFINAE sagt "Substitutionsfehler ist kein Fehler" - genau das haben Sie getan. Die Verwendung von sizeof, damit der Compiler Vorlagenargumente in einen Ausdruck einfügt, ohne ihn tatsächlich auszuführen, ist ebenfalls üblich.

Leider :-)