The question stays the same - Can we detect overloaded member functions, without specifying their arguments, or using mentioned trick? I know I'm maybe asking for impossible, but it never hurts to ask
Actually, it is not impossible.
It follows a minimal, working example:
template<typename T, typename R, typename... A>
void proto(R(T::*)(A...));
template<typename, typename = void>
constexpr bool has_single_f = false;
template<typename T>
constexpr bool has_single_f<T, decltype(proto(&T::f))> = true;
struct S {
void f(int) {}
void f(char) {}
};
struct U {
void f() {}
};
int main() {
static_assert(not has_single_f<S>, "!");
static_assert(has_single_f<U>, "!");
}
Of course, you need to add more stuff to distinguish between member methods and data members, but it's trivial to add them (see the header type_traits
) and I tried to keep the example as minimal as possible.
The basic idea is that the call to proto
fails if the given function is overloaded, for it's an ambiguous call.
Anyway, the error is discarded because of SFINAE rules.
Arguments are not required to be specified as requested.
Note also that proto
does not require to be defined, but it's important that its return type is void
. Otherwise you have to slightly modify the call to decltype
as it follows:
template<typename T>
constexpr bool has_single_f<T, decltype(proto(&T::f), void())> = true;
As you can see from the example code, the static_assert
s verify that f
is overloaded in S
and it is not in U
.
The example above is based on template variables, that are part of the language since C++14.
If you prefer the well known struct based solution that works with C++11, you can use the following detector:
#include<type_traits>
//...
template<typename, typename = void>
struct has_single_f: std::false_type {};
template<typename T>
struct has_single_f<T, decltype(proto(&T::f))>: std::true_type {};
//...
int main() {
static_assert(not has_single_f<S>::value, "!");
static_assert(has_single_f<U>::value, "!");
}