Es gibt hier viele Antworten, aber ich habe keine Version gefunden, die funktioniert real Methodenauflösungsreihenfolge, wobei keine der neueren C++-Funktionen verwendet wird (nur C++98-Funktionen).
Hinweis: Diese Version ist getestet und funktioniert mit vc++2013, g++ 5.2.0 und dem onlline Compiler.
Also habe ich mir eine Version ausgedacht, die nur sizeof() verwendet:
template<typename T> T declval(void);
struct fake_void { };
template<typename T> T &operator,(T &,fake_void);
template<typename T> T const &operator,(T const &,fake_void);
template<typename T> T volatile &operator,(T volatile &,fake_void);
template<typename T> T const volatile &operator,(T const volatile &,fake_void);
struct yes { char v[1]; };
struct no { char v[2]; };
template<bool> struct yes_no:yes{};
template<> struct yes_no<false>:no{};
template<typename T>
struct has_awesome_member {
template<typename U> static yes_no<(sizeof((
declval<U>().awesome_member(),fake_void()
))!=0)> check(int);
template<typename> static no check(...);
enum{value=sizeof(check<T>(0)) == sizeof(yes)};
};
struct foo { int awesome_member(void); };
struct bar { };
struct foo_void { void awesome_member(void); };
struct wrong_params { void awesome_member(int); };
static_assert(has_awesome_member<foo>::value,"");
static_assert(!has_awesome_member<bar>::value,"");
static_assert(has_awesome_member<foo_void>::value,"");
static_assert(!has_awesome_member<wrong_params>::value,"");
Live-Demo (mit erweiterter Rückgabetypenprüfung und vc++2010-Workaround): http://cpp.sh/5b2vs
Keine Quelle, da ich selbst darauf gekommen bin.
Wenn Sie die Live-Demo auf dem g++-Compiler ausführen, beachten Sie bitte, dass Array-Größen von 0 erlaubt sind, was bedeutet, dass das verwendete static_assert keinen Compiler-Fehler auslöst, selbst wenn es fehlschlägt.
Eine häufig verwendete Umgehungslösung besteht darin, das "typedef" im Makro durch "extern" zu ersetzen.