Is there an adequate way in C++ to extract a hash from the data that std::any stores? Well, or at least an object in the form of a list of bytes and its length
-
2Can you explain why you want this? Have you considered computing the hashes you want before inserting values into the `std::any` and storing them together in something like `struct HashedValue { std::size_t hash; std::any value };`? – alter_igel Apr 06 '21 at 16:21
-
1@alterigel: Wouldn't doing that risk undue collisions? I mean, AFAICR, type information is not hashed together with the actual value. – einpoklum Apr 06 '21 at 16:27
-
1@einpoklum: Assuming good hashing functions, adding type information is only going to affect _which_ values collide. – MSalters Apr 06 '21 at 18:52
-
@MSalters Yes. For example, the C # Dictionary considers int(1) and long (1) to be different objects – uselessgoddess Apr 07 '21 at 12:51
1 Answers
std::any
is a type-safe mechanism for passing an object of known type from one location to another, through an intermediary that does not need to know what that type is. Computing a hash from it is not its goal. And indeed, it wouldn't be meaningfully possible without compromising any
's functionality.
Hashing an object requires some knowledge of what that object is and is doing. Assuming that you can just look at the bytes of the object representation and thereby compute a meaningful hash from it is not going to end well. It might appear to work... for a while. But eventually, it's going to do the wrong thing.
You could create a type-erased type similar to any
that requires the object to implement hashing. But std::any
is not that type, because anyone who doesn't want to hash the types they put into any
would be unable to store said object in any
.
This is because any operation that any
provides is an operation that all types that gets stored into any
must also provide. For example, any
is copyable, therefore any
cannot store move-only types. That is an annoyance for those who want to do so, and the more functionality you dump into any
, the more restrictive the type's ability to store "any"thing becomes.

- 449,505
- 63
- 781
- 982
-
4@KonradRudolph: "*It’s entirely legitimate to want to use std::any as a dictionary key type*" No, it's legitimate to want to have a type-erased dictionary key type for hash containers. That `std::any` is meant to be or *ought to be* that type is another discussion entirely. I remind you that any functionality that `any` is required to have is functionality that all things you put into `any` *must have*. If `any` is hashable, then all types put into `any` must also be hashable. So even if I never use its hash functionality, my types must still be hashable. – Nicol Bolas Apr 06 '21 at 16:17
-
3@KonradRudolph: `any` doesn't require the types in question to be equality-comparable, which is why `any` cannot be equality-compared. A statically typed language is simply not an appropriate place for some kind of omni-erased-type that can forward every operation to the type-erased object. Especially if you only want that functionality to be conditionally available. – Nicol Bolas Apr 06 '21 at 16:20
-
@KonradRudolph: "forwarding such operations to the underlying type as required", is somewhat problematic; I agree with Nicol that it should not be `any`'s responsibility to cater to this, especially as far as you expect. That being said - there should be some way to hash type-erased values. Perhaps a hashing of their serialization? – einpoklum Apr 06 '21 at 16:30
-
If using std:: any to do this is problematic, can such an implementation fix it? https://godbolt.org/z/3Wc58oarK (I want to make an analog of Dictionary – uselessgoddess Apr 06 '21 at 16:36
-
1@dodickgod: If we ignore the complete lack of type safety in that code, it would work to the extent outlined in my answer. Namely, it would *require* that anything you store in your wrapper be a hashable type. But don't forget that the types need to be equality comparable, since a hash table has to equality test the values. So you need to properly type-erase equality testing, particularly between objects of different types. – Nicol Bolas Apr 06 '21 at 16:39
-
@NicolBolas "I think using the std_hashable concept will solve this problem" – uselessgoddess Apr 06 '21 at 16:42
-
@dodickgod: Considering that the equality testing part is the harder issue, I fail to see how that would help. – Nicol Bolas Apr 06 '21 at 16:43
-
`return 0;` is a valid hash, and `return true;` is a valid equality comparison, so you can have a wrapper like `std::any`. It will be *bad* for non-equatable / non-hashable values – Caleth Apr 06 '21 at 16:45