[C++0x/SFINAE] Feststellen, ob eine bestimmte Member-Funktion existiert?
-
Guten Abend
Aus aktuellem Anlass in einem Projekt (und natürlich auch aus Interesse an den nahezu experimentalen Eigenheiten von C++) wollte ich ein portables Template programmieren, welches feststellt, ob der angegebene Typ
Teine bestimmte Member-FunktionT::invokein der Formvoid (T::*)() constbereitstellt. Hierzu habe ich unter dem Stichwort SFINAE (engl. "Substitution Failure Is Not An Error") einige Beispiele gefunden, welche allerdings bei mir prompt nicht kompilierbar waren. Also habe ich die Sache selbst in die Hand genommen und die folgenden Templates geschrieben:template<typename query_target_type, void (query_target_type::*)() const> struct sfinae_entity; template<typename query_target_type> true_type sfinae_invoke(sfinae_entity<query_target_type, &query_target_type::invoke> *); template<typename> false_type sfinae_invoke(...); template<typename query_target_type> struct has_invoke_method { typedef decltype(sfinae_invoke<query_target_type>(0)) type; };Obiger Code macht sich den Umstand zu Nutze, dass C++-Compiler bei der Überladung von Funktionen eigentlich fehlerhafte Template-Anwendungen komplett ignorieren, wenn eine andere Variante bevorzugt werden kann. Wenn also das Template
sfinae_entityals Parameter insfinae_invokekeinen Sinn ergibt, wird die Überladung verworfen und die allgemeine Variante gewählt.Mit diesen Templates habe ich dann folgendes Test-Programm geschrieben und sowohl mit GCC 4.4.5, als auch mit Visual C++ 2010 zum Laufen gebracht, wobei das Resultat wie gewünscht und erwartet mit beiden Compilern dasselbe ist:
struct foo { void invoke() const { cout << "TEST" << endl; } }; struct bar { }; int main() { // Gibt 1 und 0 aus. cout << has_invoke_method<foo>::type::value << endl << has_invoke_method<bar>::type::value << endl; }Wie portabel ist diese Art der Programmierung wirklich? Kann man sich darauf verlassen, dass sowas mit allen konformen Compilern laufen wird? Ich frage, weil die alten Beispiele nicht laufen wollten.
Mit freundlichen Grüssen
-
Falls du diesen Artikel noch nicht gefunden hast:
Mehr hab' ich auf die Schnelle nicht anzubieten.
Was Konformität angeht: mit einem konformen Compiler wirst du im Moment dein Beispiel gar nicht compilieren können, da decltype ein C++0x Feature ist, und C++0x ist noch nicht Standard
-
Ich konnte auch einen Artikel ausgraben:
-
Danke für die beiden Artikel. Der erste von hustbaer scheint ja erstaunlich nahe an meinem Code zu sein, abgesehen von der Verwendung von
decltype, was meiner Meinung nach ein wenig eleganter ist (aber natürlich noch nicht konform; überhaupt weiss ich nicht, ob ichdecltypeso einsetzen darf...) als der weithin bekanntesizeof-Hack. Beim CodeProject-Artikel gibts noch ein schönes Select-Template, was ich in dieser Form gebrauchen könnte, aber mal schauen, ob TR1 nicht bereits sowas anbietet.
hustbaer schrieb:
Was Konformität angeht: mit einem konformen Compiler wirst du im Moment dein Beispiel gar nicht compilieren können, da decltype ein C++0x Feature ist, und C++0x ist noch nicht Standard

Dann wird es Zeit, dass ich denen mal Feuer unter dem Hintern mache, weil mein Code hier bereits an diversen Stellen Dinge wie
auto,decltypeund Lambda-Ausdrücke verwendet. Im Prinzip hast du natürlich Recht, dass ich mit der Konformität ein wenig früh dran bin. Ich versuche C++0x zu programmieren, was schwierig ist, wenn der Standard noch nicht verabschiedet ist
