指针值的严格弱排序

时间:2019-01-15 15:20:37

标签: c++ set strict-weak-ordering

请考虑以下结构:

struct Foo {
  const Bar* x;
  const Bar* y;

  Foo(const Bar* _x, const Bar* _y = nullptr) : x(_x), y(_y) { assert(x); }
}

我们如何在x和y上定义严格的弱排序,以便可以在std :: set中使用该对象?请注意,y可以为空指针。如Using std::less with nullptr中所述,空指针上std :: less的行为是 undefined 未指定。以下解决方案是否足够?

bool operator<(const Foo& rhs) const {
  uintptr_t numX = reinterpret_cast<uintptr_t>(x);
  uintptr_t numY = reinterpret_cast<uintptr_t>(y);

  uintptr_t numRhsX = reinterpret_cast<uintptr_t>(rhs.x);
  uintptr_t numRhsY = reinterpret_cast<uintptr_t>(rhs.y);

  return std::tie(numX, numY) < std::tie(numRhsX, numRhsY);
}

编辑:如果不是,正确的方法是什么(例如,如何将std :: less与std :: tie结合起来)?

1 个答案:

答案 0 :(得分:3)

使用std::less<Bar*>就足够了(但不能使用operator<)。 std::less的指针专长(如the accepted answer to "Using std::less with nullptr"所指出的)保证了总排序。与nullptr的比较是未指定,这意味着标准没有强加特定的顺序,但是std::less仍必须产生 a 总排序(对于给定的指针pp < nullptr每次必定产生相同的值)。

由于总排序要比弱排序强,因此在您的情况下使用std::less就足够了。

  

编辑:如果不是,正确的方法是什么(例如,如何将std :: less与std :: tie结合起来)?

不幸的是,没有整齐的方法。由于std::tie返回一个std::tuple,并且元组的比较是根据其值的operator<(而不是std::less)定义的,因此您不能真正使用{{1 }} 这里。要使用std::tie,您必须手动进行:

std::less

顺便说一句,您当前的实现(将指针重新解释为整数)也会产生总排序(显然,因为您正在比较整数),但是除了 unspecified 行为外,您还会得到实施定义的行为(来自bool operator<(const Foo& rhs) const { if (std::less<>{}(x, rhs.x)) return true; if (std::less<>{}(rhs.x, x)) return false; return std::less<>{}(y, rhs.y); } )。