I want to use triplets to be elements of unordered_set
. I want to check whether a combination of three values has been present or not:
unordered_set<long, long, long> myset;
myset.insert(0, 1, 0);
Obviously that's not correct. How could I do this correctly? Thank you for your help.
-------Updated-------
If I don't use unordered_set
, is there any other easier way to check whether a combination has been present or not?
Thank you for your help.
CodePudding user response:
From the std, you probably want to use std::unordered_set<std::tuple<long, long, long>, Hasher>
or std::unordered_set<std::array<long, 3>, Hasher>
.
That said, as suggested by @Evg, a struct would hold more meaning.
If you look at std::unordered_set's documentation you can see that it takes the element only as the first template parameter, the others are used for other types.
Unfortunately as @Evg pointed out, these types need a custom hasher. Here is a hasher's basic structure:
struct Hasher {
// v Here goes your set's type
std::size_t operator()(std::tuple<long, long, long> const& key) const {
return /* the hash */;
}
};
You can find an implementation example at cppreference's hash page.
CodePudding user response:
First you should define hash function for such an element. I'm not a big expert in hashing, but standard approach would look something like this:
using el_type = std::tuple<long, long, long>;
const auto hash = [] (const el_type& element) {
return std::hash<long>{}(std::get<0>(element)) ^
(std::hash<long>{}(std::get<1>(element)) << 1) ^
(std::hash<long>{}(std::get<2>(element)) << 2);
};
And that should be enough as long as the elements type have a viable ==
overload (so you don't have to provide custom equal
function as well):
std::unordered_set<el_type, decltype(hash)> set{ 4, hash };
set.emplace(1, 2, 3); // std::pair<it, true> - inserted
set.emplace(0, 0, 1); // std::pair<it, true> - inserted
set.emplace(0, 0, 1); // std::pair<it, false> - insertion didn't happen