3

In Qt I had the brilliant (cough, cough) idea to start defining overloads of qHash (the hashing function used for QHash, one of Qt's associative containers) for Standard Library datatypes: std::basic_string, std::shared_ptr and the like.

There could be a shortcut for this process: instead of chasing "any Standard Library type that could be used as a key in QHash" and adding a qHash overload for it, I could just define qHash automatically if the type has a std::hash specialization for it (reasonably assuming that we don't want to do more than what the Standard Library does in this process).

That is, I could implement something like this using expression SFINAE:

template<typename T>
auto qHash(const T &t) -> decltype(std::hash<T>()(t)) 
{ 
    return std::hash<T>()(t); 
}

Unfortunately, although Qt demands a C++11 compiler, expression SFINAE is not allowed anywhere because MSVC does not fully support it (at the time of this writing: all MSVC versions, up to and including VS15 preview 5. Anyhow, Qt must support all the way back to 2013).

Hence, the question: is there a way to do the same, in a way that

  1. does not use expression SFINAE
  2. is guaranteed to work on all MSVC versions >= 2013?

I was thinking a plain good ol' C++98 SFINAE construction via enable_if and the like, but other SO answers (like this one) make me think that MSVC 2013 may miscompile that too, so the result becomes unacceptable again.

peppe
  • 21,934
  • 4
  • 55
  • 70
  • https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ – πάντα ῥεῖ Nov 08 '16 at 17:57
  • Try tag dispatching. Have your `qHash` tag-dispatch on "can I `std::hash`" to either an implementation that uses `std::hash`, or one that does not. Repeat for each thing you are testing for. – Yakk - Adam Nevraumont Nov 08 '16 at 18:22
  • You can SFINAE on `std::hash::result_type` i think, which by definition for the std-provided specializations of `std::hash` is always `std::size_t`. That should work even with primitive compilers. – sbabbi Nov 08 '16 at 18:22
  • https://blogs.msdn.microsoft.com/vcblog/2016/06/07/expression-sfinae-improvements-in-vs-2015-update-3/ – Hans Passant Nov 08 '16 at 18:28
  • 1
    @HansPassant: that's about MSVC 2015, not 2013. Neither of them claim expression SFINAE support, so we can't use it. :( – peppe Nov 08 '16 at 19:14

1 Answers1

2

I do not think you need expression SFINAE for this, something along these lines should work.

template<typename T>
typename std::hash<T>::result_type qHash(const T &t) 
{ 
     return std::hash<T>()(t); 
}

Or pretty much any approach that does SFINAE on hash::result_type. Unfortunately for you, hash::result_type is deprecated in C++17, but you can still #ifdef this code for MSVC 2013.

sbabbi
  • 11,070
  • 2
  • 29
  • 57