In my program I want that the default value, if a key doesn't exist in my unordered map, is going to be std::numeric_limits<double>::max()
Instead of just 0.
my code looks like the following:
class Pair
{
public:
Graph::NodeId node;
bitset<64> bits;
Pair(Graph::NodeId node1, double bits1)
{
node = node1;
bitset<64> temp(bits1);
bits = temp;
}
};
bool operator==(const Pair &P1, const Pair &P2)
{
return P1.node == P2.node && P1.bits == P2.bits;
}
template <>
struct std::hash<Pair>
{
std::size_t operator()(const Pair &pair) const noexcept
{
std::hash<decltype(pair.node)> ihash;
std::hash<decltype(pair.bits)> bhash;
return ihash(pair.node) * 31 bhash(pair.bits);
}
};
unordered_map<Pair, double> lFunction;
so if I want to access the element lFunction[Pair(3,3)]
and the key doesn't exist, there should be the value std::numeric_limits<double>::max()
.
CodePudding user response:
One possibility would be to create a tiny class for the value type:
class dproxy {
double value_;
public:
dproxy(double value = std::numeric_limits<double>::max())
: value_{value} {}
operator double &() { return value_; }
operator double const &() const { return value_; }
};
std::unordered_map<Pair, dproxy> lFunction;
A default-constructed dproxy
will be initialized to std::numeric_limits<double>::max()
, and a dproxy will implicitly convert to a (reference to a) double
. This can impose limitations if you're doing a lot of implicit conversions otherwise though (e.g., if you had some other function foo
that took some other type bar
that could be implicitly constructed from a double
, foo(lFunction[baz]);
would work if lFunction
contained double
s, but not if it contained dproxy
objects, since an implicit conversion sequence can only use one user-defined conversion).
CodePudding user response:
if I want to access the element
lFunction[Pair(3,3)]
and the key doesn't exist, there should be the valuestd::numeric_limits<double>::max()
.
std::unordered_map::operator[]
simply does not work that way. When it needs to insert a new value for a missing key, the new value is always value-initialized, which for numeric types means 0
. There is no option to change that behavior in the unordered_map
itself. But @JerryCoffin's answer shows you a workaround to take advantage of that behavior so you can define your own default value.
Otherwise, the alternative is to simply not use the map's operator[]
at all. Use its find()
and emplace()
methods instead, eg:
auto getFunctionValue = [&](const Pair &key)
{
auto iter = lFunction.find(key);
if (iter == lFunction.end()) {
iter = lFunction.emplace(key, std::numeric_limits<double>::max()).first;
// or simply:
// return std::numeric_limits<double>::max();
}
return iter->second;
};
//double d = lFunction[Pair(3,3)];
double d = getFunctionValue(Pair(3,3));
...
Or, if you are using C 17 or later, you can use the try_emplace()
method instead, eg:
auto getFunctionValue = [&](const Pair &key)
{
return lFunction.try_emplace(key, std::numeric_limits<double>::max()).first->second;
};
//double d = lFunction[Pair(3,3)];
double d = getFunctionValue(Pair(3,3));
...