With std::experimental::is_detected
and std::experimental::disjunction
you could do this:
//check for a type member named foo
template <typename T>
using foo_type_t = typename T::foo;
//check for a non-type member named foo
template <typename T>
using foo_non_type_t = decltype(&T::foo);
template <typename T>
using has_foo = disjunction<is_detected<foo_type_t, T>,
is_detected<foo_non_type_t, T>>;
Then you would use has_foo<my_class>::value
in whatever you want.
The above will work for more than just types and member functions, but you could easily constrain it by using traits like std::is_member_function_pointer
and std::is_member_object_pointer
if you like.
To supply your optional argument, you could use the std::experimental::is_detected_exact
helper.
Live Demo
Note that if you take the implementations of the above traits from the pages I linked, you can use this with C++14. A minor change to the disjunction
code will let you use it in C++11.