C++ allows SFINAE to be used for this:
#define HAS_MEM_FUNC(func, name) \
template<typename T, typename Sign> \
struct name { \
template <typename U, U> struct type_check; \
template <typename _1> static char (& chk(type_check<Sign, &_1::func> *))[1]; \
template <typename > static char (& chk(...))[2]; \
static bool const value = sizeof(chk<T>(0)) == 1; \
}
the above template and macro tries to instantiate a template, giving it a member function pointer type, and the actual member function pointer. If the types to not fit, SFINAE causes the template to be ignored. Usage like this:
HAS_MEM_FUNC(toString, has_to_string);
template<typename T> void
doSomething() {
if(has_to_string<T, std::string(T::*)()>::value) {
...
} else {
...
}
}
But note that you cannot just call that toString
function in that if branch. since the compiler will check for validity in both branches, that would fail for cases the function doesnt exist. on way is to use sfinae once again (enable_if can be gotten from boost too):
template<bool C, typename T = void>
struct enable_if {
typedef T type;
};
template<typename T>
struct enable_if<false, T> { };
HAS_MEM_FUNC(toString, has_to_string);
template<typename T>
typename enable_if<has_to_string<T,
std::string(T::*)()>::value, std::string>::type
doSomething(T * t) {
/* something when T has toString ... */
return t->toString();
}
template<typename T>
typename enable_if<!has_to_string<T,
std::string(T::*)()>::value, std::string>::type
doSomething(T * t) {
/* something when T doesnt have toString ... */
return "T::toString() does not exist.";
}
Have fun using it. The advantage of it is that it also works for overloaded member functions, and also for const member functions (remember using std::string(T::*)() const
as the member function pointer type then!).