std map复合键

时间:2012-04-23 07:20:10

标签: c++ stdmap

我遇到了std :: map所需的运算符<()方法的问题。我使用结构作为复合键,如下所示:

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;
  }
}

如前所述,我想使用具有4个值的复合键,但我不知道如何为运算符&lt; 方法实现此目的。我发现一次只存储1个值!

有人可以告诉我正确的情况如何?

提前致谢!

3 个答案:

答案 0 :(得分:8)

标准库的关联容器,例如std::mapstd::setstd::multisetstd::multimapstd::bitset需要订购元素必须遵循Strict Weak Ordering,这意味着您operator<的实施必须遵循strict weak ordering。所以一个实现可能是这样的:

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;
}

或者您可以将其实现为:

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;
}

在此解决方案中,std::tie函数创建了传递给它的参数的两个元组t1t1,然后比较t1和{{1}使用重载t2代替operator<。元组的operator<按字典顺序比较元素 - 实现严格弱序排列。

答案 1 :(得分:2)

我认为你有一个问题,即运营商&lt;不一定实现严格的弱排序。 A<B为假且B<A也为假的组合太多,其中ABMyKey个对象。这被解释为A等于B

答案 2 :(得分:2)

您的实施问题是它不稳定,请考虑......

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

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

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

因此,尽管它们在map中不是等号键,但两者都没有报告为低于另一个。

一个有效的解决方案:只需一次完成每个必要的字符串比较,它简洁有效......

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;
}