Int and uint compare equal but hashes do not
- Dominant language
- C++
- Stars
- 50.6k
- Forks
- 7.5k
- Avg merge
- 4d 17h
- Merged PRs (30d)
- 58
Description
Description
On the implementation of std::hash, the C++ specification states:
If
k1 == k2istrue,h(k1) == h(k2)is alsotrue
Yet this is not the case for json values of the same numeric value but of signed and unsigned storage types. I can see this behaviour is documented here, but it violates the std::hash contract. While this behaviour is great for distinguishing between the other types, it feels unnatural for it to distinguish between signed and unsigned types.
Reproduction steps
using namespace nlohmann;
int main()
{
const json a{42};
const json b{42u};
assert(a == b);
assert(std::hash<json>{}(a) == std::hash<json>{}(b));
}
Expected vs. actual results
I would expect assert(std::hash<json>{}(a) == std::hash<json>{}(b)); to succeed because a == b is true, but it actually fails.
I believe the hash<basic_json> implementation should treat signed and unsigned integers the same. This is especially important because the storage type selected by the parser is not specified (currently, see #5255 ).
In all other aspects, signed and unsigned integers are treated the same: there is no distinction made in the JSON standard and they are silently cast between when calling .at() or .get<>().
Minimal code example
// I'd like to be able to write code like this
using namespace nlohmann;
int main()
{
const json j = R"({"a": 42})"_json;
const std::unordered_map<json, std::string> m = {{42, "hello"}};
std::cout << m.at(j.at("a")) << '\n'; // throws std::out_of_range
}
Error messages
Compiler and operating system
GCC 12.2.0, Linux
Library version
3.12.0
Validation
- The bug also occurs if the latest version from the
developbranch is used. - I can successfully compile and run the unit tests.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the hash<basic_json> implementation and reproduce the issue with the signed and unsigned 42 examples from the report. Review the linked pull request, then run the relevant unit tests; done means equal json values produce equal hashes and the unordered_map lookup succeeds.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- api
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100