I would like to make a type trait for checking if a particular type is hashable using the default instantiations of the standard library's unordered containers, thus if it has a valid specialization for std::hash
. I think this would be a very useful feature (e.g. for using std::set
as failsafe for std::unordered_set
in generic code). So I, thinking std::hash
is not defined for each type, started making the following SFINAE solution:
template<typename T> std::true_type hashable_helper(
const T&, const typename std::hash<T>::argument_type* = nullptr);
template<typename T> std::false_type hashable_helper(...);
//It won't let me derive from decltype directly, why?
template<typename T> struct is_hashable
: std::is_same<decltype(hashable_helper<T>(std::declval<T>())),
std::true_type> {};
(Forgive my modest SFINAE-abilities if this is not the best solution or even wrong.)
But then I learned, that both gcc 4.7 and VC++ 2012 define std::hash
for any type T
, just static_assert
ing in the non-specialized version. But instead of compiling conditionally they (and also clang 3.1 using gcc 4.7's libstdc++) fail the assertion resulting in a compile error. This seems reasonable since I think static_assert
s are not handled by SFINAE (right?), so an SFINAE solution seems not possibly at all. It's even worse for gcc 4.6
which doesn't even have a static_assert
in the general std::hash
template but just doesn't define its ()
operator, resulting in a linker error when trying to use it (which is always worse than a compile error and I cannot imagine any way to transform a linker error into a compiler error).
So is there any standard-conformant and portable way to define such a type trait returning if a type has a valid std::hash
specialization, or maybe at least for the libraries static_assert
ing in the general template (somehow transforming the static_assert
error into a SFINAE non-error)?