Just call the member function and discard the result in the SFINAE context. If this succeeds, the method exists. If this fails, the method does not work.
// not needed in C++1y template<class T,class V=void>using enable_if_t=typename enable_if<T,V>::type; // If the other tests fail, the type T does not have a method `foo` of // signature Sig. The class=void parameter is an implementation detail // that in an industrial quality implementation we would hide in a helper // template type. template<class T,class Sig,class=void>struct has_foo:std::false_type{}; // For R(Args...), we attempt to invoke `T::foo` with (Args...), then check // if we can assign the return value to a variable of type R. template<class T,class R,class...Args> struct has_foo<T,R(Args...), enable_if_t< // std:: in C++1y std::is_convertible< decltype( T::foo( std::declval<Args>()... ) ), R >::value && !std::is_same<R, void>::value > >: std::true_type {}; // for `void` return value, we only care if the function can be invoked, // no convertible test required: template<class T,class...Args> struct has_foo<T,void(Args...), decltype( void(T::foo( std::declval<Args>()... ) ) ) >: std::true_type {};
using:
has_foo< bar, int(int) >::value
which checks if int r = T::foo( 7 )
valid expression, and not for exact signature matching.
source share