To detect existence of class members usual approach is to use std::void_t
template. You can do it like this:
#include <iostream>
#include <type_traits>
class Test1
{
public:
void method();
};
class Test2
{
public:
void method();
void method(int);
};
template <typename T, typename = void>
struct HasMethod : std::false_type
{
};
// Use method(0) to detect void method(int) overload
// You don't even need std::void_t in this case, since method returns void anyway, but for any other return type you will need it
template <typename T>
struct HasMethod<T, std::void_t<decltype(std::declval<T>().method())>>
: std::true_type
{
};
int main()
{
std::cout << HasMethod<Test1>::value << std::endl; // prints 1
std::cout << HasMethod<Test2>::value << std::endl; // prints 1
}
Ok. After some thinking I found solution. We can use fact that declval(&T::method)
will fail, if there is more than one overload, to detect if we have at least one overload, by adding another one. Here is solution. It is quite verbose, but I was unable to reduce it. At least it works.
#include <iostream>
#include <type_traits>
class Test
{
};
class Test1
{
public:
void method();
};
class Test2
{
public:
void method();
void method(int);
};
class Test3
{
public:
using method = int;
};
class Test4
{
public:
int method;
};
template<typename T, typename = void>
struct HasSingleOverload : std::false_type {};
template<typename T>
struct HasSingleOverload<T, std::void_t<decltype(&T::method)>> : std::true_type {};
template<typename T, typename = void>
struct IsMemberFunction : std::false_type {};
template<typename T>
struct IsMemberFunction<T, std::enable_if_t<std::is_member_function_pointer<decltype(&T::method)>::value>> : std::true_type {};
template<typename T, typename = void>
struct IsType : std::false_type {};
template<typename T>
struct IsType<T, std::void_t<typename T::method>> : std::true_type {};
struct HasOverload {
void method();
};
template<typename T>
struct CheckOverload : T, HasOverload {
};
template<typename T>
using HasConflict = std::bool_constant<!HasSingleOverload<CheckOverload<T>>::value>;
template<typename T>
using HasAnyOverload = std::conditional_t<HasSingleOverload<T>::value || IsType<T>::value, IsMemberFunction<T>, HasConflict<T>>;
int main()
{
std::cout << HasAnyOverload<Test>::value << std::endl; // prints 0
std::cout << HasAnyOverload<Test1>::value << std::endl; // prints 1
std::cout << HasAnyOverload<Test2>::value << std::endl; // prints 1
std::cout << HasAnyOverload<Test3>::value << std::endl; // prints 0
std::cout << HasAnyOverload<Test4>::value << std::endl; // prints 0
}