I personally use that (which use full signature):
#include
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template \
class traitsName \
{ \
private: \
template struct helper; \
template \
static std::uint8_t check(helper*); \
template static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check(0)) == sizeof(std::uint8_t); \
}
So in your case, use something like:
DEFINE_HAS_SIGNATURE(has_func_name, T::func_name, void (T::*)(Args...));
And test it like:
struct C
{
void func_name(char, int);
};
static_assert(has_func_name::value, "unexpected non declared void C::func_name(char, int)");
static_assert(!has_func_name::value, "unexpected declared void C::func_name(int, int)");