I am setting up an unordered_map, in which the key is an enum of Direction defined as:
enum Direction : uint16_t {
North = 1 << 0,
East = 1 << 2,
South = 1 << 3,
West = 1 << 4,
None = 1 << 5,
};
The goal is to check if at least 2 of these flags are set, but up to n flags set.
With my enum defined above, I attempt to create a number of unordered_maps
std::unordered_map<Direction, std::vector<Tile*>>* groundTiles;
std::unordered_map<Direction, std::vector<Tile*>>* northEastHillTiles;
std::unordered_map<Direction, std::vector<Tile*>>* southEastHillTiles;
std::unordered_map<Direction, std::vector<Tile*>>* platformTiles;
std::unordered_map<Direction, std::vector<Tile*>>* wallTiles;
I initialize them as
groundTiles = new std::unordered_map<Direction, std::vector<Tile*>>();
groundTiles->insert_or_assign(Direction::None, std::vector<Tile*>());
groundTiles->insert_or_assign(Direction::East, std::vector<Tile*>());
groundTiles->insert_or_assign(Direction::West, std::vector<Tile*>());
groundTiles->insert_or_assign((Direction)(Direction::East|Direction::West),std::vector<Tile*>());
and so on for the other sets
However, when I try to pull a Tile from the ground ( or any other set ) I cannot check if at least Direction::East and Direction::West are set. I have tried:
Tile* westAndEastCapped = southEastHillTiles->at((Direction)(Direction::West | Direction::East)).at(0);
But it seems to just default to the Direction::East set.
How can I select a tile from an unordered_map, with BOTH East and West flags set, and no others?
This is not how std::unordered_map::at()
works. It only retrieves a value from the unordered map for a key that's equal to the passed in parameter. Equal as in "exactly". That's it. Nothing else.
Additionally, at()
throws an exception if the specified key does not exist.
All that std::unordered_map
knows about it's key is that it's some kind of an opaque value. std::unordered_map
doesn't care about any interpretation or meaning of the key, except that the only thing that std::unordered_map
requires from its key is that it has an equality comparison and that it has a hash function.
An enum
meets those requirements. The End. Just because this particular enum
is interpreted as a bitmask, of some sorts, means nothing to a std::unordered_map
.
A std::unordered_map
is not well-suited for the way you're trying to access its values, it's not going to work. You will likely need to design a custom container for your values that will implement the desired access pattern efficiently.
In the worst case you can always resort to range iteration:
for (auto &[key, value]: southEastHillTiles)
{
// ...
}
and then inspect each present key
in the map to determine if it qualifies for what you're searching for. This is horribly inefficient, but that's pretty much the only thing that can be done with an unordered_map
.