Home > Back-end >  set default value of unordered map if key doesn't exist
set default value of unordered map if key doesn't exist

Time:06-30

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 doubles, 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 value std::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));
...
  • Related