#include <iostream>
#include <type_traits>

#define declare_member_check(name, ret_type, /*args*/ ...) \
namespace member_check{ \
template <typename T> \
struct has_##name \
{ \
    template <typename U> static std::true_type test(decltype(&U::name)); \
    template <typename U> static std::false_type test(...); \
    static constexpr bool value = std::is_same<decltype(test<T>(nullptr)), std::true_type>::value; \
};\
}\

struct Test {
    const std::string &print(const std::string &str, void *pointer, int *second) {
        std::cout<<str<<std::endl;
        return str;
    }
};

struct Test2 {
    void show_msg(){}
};

declare_member_check(show_msg, void);
declare_member_check(print, const std::string &, const std::string &, void *, int *);

int main()
{
    std::cout << "Check show_msg" << std::endl;
    std::cout << "Test: " << (member_check::has_show_msg<Test>::value ? "yes" : "no") <<std::endl;
    std::cout << "Test2: " << (member_check::has_show_msg<Test2>::value ? "yes" : "no") <<std::endl;

    std::cout << "Check print msg" << std::endl;
    std::cout << "Test: " << (member_check::has_print<Test>::value ? "yes" : "no") << std::endl;
    std::cout << "Test2: " << (member_check::has_print<Test2>::value ? "yes" : "no") << std::endl;

    return 0;
}