#include <iostream>
#include <type_traits>
#include <typeinfo>

using namespace std;

#define FOO(FUNCTION, DEFINE) template <typename T, typename S = decltype(declval<T>().FUNCTION)> static true_type __ ## DEFINE(int); \
                              template <typename T> static false_type __ ## DEFINE(...); \
                              template <typename T> using DEFINE = decltype(__ ## DEFINE<T>(0));
#define BAR(CLASS, FUNCTION) [] {struct { \
    template<typename R, typename S = decltype(declval<R>().FUNCTION)> static true_type Test(R*); \
    template<typename R> static false_type Test(...); \
    operator bool() const { return decltype(Test<CLASS>(0))::value; } } result; \
    return result; }()

namespace details {
    FOO(test(declval<int>()), test_int)
    FOO(test(), test_void)
}

struct a {
    void test();
    void test(int);
};

struct b {
    int test(double);
};

struct c {
    void test();
};

template <typename T> enable_if_t<details::test_int<T>::value, void> outputInt() { cout << typeid(T).name() << " yes\n"; }
template <typename T> enable_if_t<!details::test_int<T>::value, void> outputInt() { cout << typeid(T).name() << " no\n"; }
template <typename T> enable_if_t<details::test_void<T>::value, void> outputVoid() { cout << typeid(T).name() << " yes\n"; }
template <typename T> enable_if_t<!details::test_void<T>::value, void> outputVoid() { cout << typeid(T).name() << " no\n"; }

int main() {
	outputInt<a>();
	outputVoid<a>();
	outputInt<b>();
	outputVoid<b>();
	outputInt<c>();
	outputVoid<c>();
	
	
    if(BAR(a, test(declval<int>()))) cout << "a yes\n";
    if(BAR(a, test())) cout << "a yes\n";
    if(BAR(b, test(declval<int>()))) cout << "b yes\n";
    if(BAR(b, test())) cout << "b yes\n";
    if(BAR(c, test(declval<int>()))) cout << "c yes\n";
    if(BAR(c, test())) cout << "c yes\n";
}