// Macro helper to create traits
#define HAS_TEMPLATED_FUNC(traitsName, funcName, Prototype) \
namespace detail { \
template<typename U> \
class traitsName \
{ \
typedef std::uint8_t yes; \
typedef std::uint16_t no; \
template <typename T, T> struct type_check; \
template <typename T = U> static yes &chk(type_check<Prototype, &funcName>*); \
template <typename > static no &chk(...); \
public: \
static bool const value = sizeof(chk<U>(0)) == sizeof(yes); \
}; \
} \
template <typename U> \
struct traitsName : std::conditional<detail::traitsName<U>::value, \
std::true_type, std::false_type>::type {}
Now assume that:
unsigned int hasher(const int& item);
Now create the trait:
HAS_TEMPLATED_FUNC(has_hasher, hasher, unsigned int (*)(const T&));
// some test.
static_assert(has_hasher<int>::value, "");
static_assert(!has_hasher<char>::value, "");
Now, there is some way to use it
Tag dispatching:
template <typename Item>
class foo
{
public:
void method()
{
method(has_hasher<Item>());
}
private:
void method(std::true_type)
{
// You may use hasher here.
hasher(Item{});
}
void method(std::false_type)
{
// You cannot use hasher here.
}
};
or SFINAE:
template <typename Item>
class foo
{
public:
template <typename T = Item>
typename std::enable_if<has_hasher<T>::value, void>::type
method()
{
// You may use hasher here.
hasher(Item{});
}
template <typename T = Item>
typename std::enable_if<!has_hasher<T>::value, void>::type
method()
{
// You cannot use hasher here.
}
};