std map composite key

巧了我就是萌 提交于 2019-12-23 21:13:10

问题


I have a problem with the operator<() method which is required for a std::map. I'm using a struct as composite key that looks as follows:

struct MyKey {
  std::string string1;
  std::string string2;
  std::string string3;
  unsigned int uint1;

  friend bool operator<(const MyKey& mk1, const MyKey& mk2)
  {
    return mk1.string1 < mk2.string1 && mk1.string2 < mk2.string2 &&
           mk1.string3 < mk2.string3 && mk1.uint1 < mk2.uint1;
  }
}

As introduced I want to use a composite key with 4 values, but I don't know how to achieve this for the operator< method. I observed that only 1 value is stored at a time!

Can anybody tell me how the right condition looks like?

Thanks in advance!


回答1:


The Standard library's associative containers such as std::map, std::set, std::multiset, std::multimap, std::bitset require that the ordering of elements must follow Strict Weak Ordering, which means your implementation of operator< must follow strict weak ordering. So one implementation could be this:

friend bool operator<(const MyKey& mk1, const MyKey& mk2)
{
  if (mk1.string1 != mk2.string1 )
       return mk1.string1 < mk2.string1;

  else if ( mk1.string2 != mk2.string2)
       return mk1.string2 < mk2.string2;

  else if (mk1.string3 != mk2.string3)
       return  mk1.string3 < mk2.string3;

  else
       return mk1.uint1 < mk2.uint1;
}

Or you can implement it as:

friend bool operator<(const MyKey& mk1, const MyKey& mk2)
{
  auto const & t1 = std::tie(mk1.string1, mk1.string2, mk1.string3, mk1.uint1);
  auto const & t2 = std::tie(mk2.string1, mk2.string2, mk2.string3, mk2.uint1);
  return t1 < t2;
}

In this solution, std::tie function creates two tuples t1 and t1 of the references of the arguments passed to it, and then compare t1 and t2 using overloaded operator< for std::tuple instead. The operator< for tuple compares the elements lexicographically — strict-weak ordering is achieved..




回答2:


I think you have a problem in that the operator< doesn't necessarily implement strict weak ordering. There are too many combinations where A<B is false and B<A is also false, where A and B are MyKey objects. This is interpreted as A being equal to B.




回答3:


The problem with your implementation is that it's not stable, consider...

return mk1.string1 < mk2.string1 && mk1.string2 < mk2.string2 &&
       mk1.string3 < mk2.string3 && mk1.uint1 < mk2.uint1;

...evaluating { "a", "a", "a", 1 } < { "a", "b", "a", 1 } = a<a && ... = false && ... = false

...but { "a", "b", "a", 1 } < { "a", "a", "a", 1 } = a<a && ... = false && ... = false

So, neither is reported as less than the other, despite them not being equal keys in the map.

A working solution: it's concise and efficient to do each necessary string comparisons only once...

friend bool operator<(const MyKey& mk1, const MyKey& mk2)
{
    int x;
    return (x = mk1.string1.compare(mk2.string1)) ? x < 0 :
           (x = mk1.string2.compare(mk2.string2)) ? x < 0 :
           (x = mk1.string3.compare(mk2.string3)) ? x < 0 :
           mk1.uint1 < mk2.uint1;
}


来源:https://stackoverflow.com/questions/10276358/std-map-composite-key

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!