请考虑以下结构:
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结合起来)?
答案 0 :(得分:3)
使用std::less<Bar*>
就足够了(但不能使用operator<
)。 std::less
的指针专长(如the accepted answer to "Using std::less with nullptr"所指出的)保证了总排序。与nullptr
的比较是未指定,这意味着标准没有强加特定的顺序,但是std::less
仍必须产生 a 总排序(对于给定的指针p
,p < 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);
}
)。