【问题标题】:Strict weak ordering on pointer values指针值的严格弱排序
【发布时间】:2019-06-09 15:20:24
【问题描述】:

考虑以下结构:

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 结合)?

【问题讨论】:

  • 我猜这与std::less 有相同的问题,因为他们都可能将nullptr 与链接问题说未指定的operator&lt; 进行比较。
  • 链接的答案确实not断言nullptr 上的std::less 是“未定义”。它特别说“未指定”,这是不同的。
  • This question 探讨了未指定和未定义行为之间的区别。
  • 在大多数实现中,nullptr 是一个等于零的值。
  • 未指定与未定义不同。只要您知道要为其编码的平台的 nullptr 为 0,这对您的设置来说是可以的,使用 std::less 就可以了。

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


【解决方案1】:

使用std::less&lt;Bar*&gt; 就足够了(但使用operator&lt; 则不行)。 std::less 的指针特化(正如the accepted answer to "Using std::less with nullptr" 指出的那样)保证了总排序。与nullptr 的比较是unspecified,这意味着标准不强制特定 排序,但std::less 仍必须产生a 总排序(对于给定的指针pp &lt; nullptr 每次都必然产生相同的值。

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

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

不幸的是,没有简洁的方法。因为std::tie 返回一个std::tuple,并且元组的比较是根据它们的值上的operator&lt; 定义的(而不是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);
}

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

【讨论】:

  • std::less 只需要 2 个参数。那我该如何组合它们呢?
  • @fliX: 使用std::tie 没有好办法,因为std::tuple 被指定为使用内置的operator&lt;
猜你喜欢
  • 2013-02-14
  • 2010-11-20
  • 2016-02-04
  • 1970-01-01
  • 2015-09-20
  • 2010-11-02
  • 1970-01-01
  • 1970-01-01
  • 2012-11-14
相关资源
最近更新 更多