If you know the exact signature of the function you are looking for, it can be solved with SFINAE (tested with clang 3.6 and gcc 4.9):
#include <stdio.h>
int SomeMethod(double d) {
// nop
return 0;
}
struct HasSomeMethod {
typedef char no[2];
template <typename C>
static auto test(C c) -> decltype(SomeMethod(c));
//static auto test(C c) -> decltype(SomeOtherMethod(c));
template <typename>
static no& test(...);
static const bool value = sizeof(test<double>(1.0)) == sizeof(int);
};
int main()
{
printf("%d\n", HasSomeMethod::value);
}
This outputs 1, and 0 if you switch the test method to the commented version.
It works with any global method as long as it has at least one parameter you can extract to a template parameter.
SFINAE is an abbreviation for "Substitution Failure Is Not An Error". Which means, you have to:
- use a template parameter which will be substituted by the compiler
- your subject must somehow depend on this template parameter
My example solves this latter by providing a templated parameter to the subject function - if there is no such function, it can't be substituted, which is valid.
Same result if there is no such overload you are looking for. You can change the parameter of SomeMethod in the code, or at the testing point, and you'll see.
Unfortunately, for this case using type_traits
, and similar tricks isn't possible. For example, the following method:
template<typename C>
static auto test(C c) -> typename std::is_same<decltype(SomeXXMethod()), decltype(c)>::type
has the same problem as your original code. For member detection this works because C::SomeMethod
depends on the template parameter.
Because of this requirement, a method with no parameter, but a non-void return type probably can be checked, but I have no idea how right now.
But if you have a void method without parameters, I'm sure you won't find a standard way to do it - you can't find any valid type specification which has both your type and that method in it.
Clang specific
If you just want a Clang specific check, there are Clang specific extensions
For example, you can use the #if __is_identifier(SomeMethod)
macro, which checks if a given identifier exists. It might be a variable, or a function, or anything, but inside this block, you can use SFINAE to decide it's type.