#include <iostream>
#include <type_traits>
template<typename CLASS>
struct has_begin
{
// NOTE: sig_matches() must come before fn_exists() as it is used for its
// type. No function bodies are needed as they are never called.
// This matching sig results in a return type of true_type
template<typename A_CLASS>
static auto
sig_matches(void(A_CLASS::*)())
-> std::true_type;
// If the member function A_CLASS::begin exists and a sig_matches() function
// exists with the required sig, then the return type is the return type of
// sig_matches(), otherwise this function can't exist because at least one
// the types don't exist so match against fn_exists(...).
template <typename A_CLASS>
static auto
fn_exists(std::nullptr_t)
-> decltype(sig_matches<A_CLASS>(&A_CLASS::begin));
// Member function either doesn't exist or doesn't match against a
// sig_matches() function.
template<typename A_CLASS>
static auto
fn_exists(...)
-> std::false_type;
// Intermediate storeage of type for clarity
typedef decltype(fn_exists<CLASS>(nullptr)) type;
// Storing the resulting value
static int const value = type::value;
};
struct A
{
void begin()
{
std::cout << "begin() called 1" << std::endl;
}
};
struct B
{
};
struct C
{
void begin()
{
std::cout << "begin() called 1" << std::endl;
}
void begin(float)
{
std::cout << "begin() called 2" << std::endl;
}
};
template<typename T, typename...ARGs>
typename std::enable_if<!!has_begin<T>::value>::type
call(ARGs...args)
{
std::cout << "Found(" << has_begin<T>::value << ")" << std::endl;
T().begin(args...);
}
template<typename T, typename...ARGs>
typename std::enable_if<!has_begin<T>::value>::type
call(ARGs...)
{
std::cout << "NOT Found(" << has_begin<T>::value << ")" << std::endl;
}
int main()
{
call<A>(); // A::begin() called
call<B>(); // B has no begin()
call<C>(); // C::begin() is not called.
return 0;
}