指针值的严格弱排序

Strict weak ordering on pointer values

考虑以下结构:

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 可以是空指针。正如 中提到的 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 结合起来)?

使用 std::less<Bar*> 就足够了(但使用 operator< 就不够了)。 std::less 的指针特化(正如 指出的那样)保证了 总排序 。与 nullptr 的比较是 未指定的,这意味着该标准不强加 特定的 排序,但 std::less 仍必须产生 a 总排序(并且对于给定的指针 pp < nullptr 必须每次都产生相同的值)。

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

EDIT: If not what is the proper way (e.g. how to combine std::less with std::tie)?

不幸的是,没有巧妙的方法。由于 std::tie returns 和 std::tuple,并且元组的比较是根据 operator< 对其值(而不是 std::less)定义的,你不能真的在这里使用 std::tie。要使用 std::less,您必须手动执行:

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

顺便说一句,您当前的实现(将指针重新解释为整数)也产生了总排序(显然,因为您正在比较整数)但是您没有 未指定 行为'将具有 实现定义的 行为(来自 reinterpret_cast)。