为什么 std::tuple 调用运算符 <=> 两次?
Why does std::tuple call operator <=> twice?
以下代码调用运算符 <=> 两次,参数颠倒。但是为什么?
GCC 10.2 和 clang 12 似乎都在使用 libstdc++-10,它的 确实提供了运算符 <=>,所以它似乎不是缺少标准库支持的情况,我的代码必须是不正确的。如何解决?
#include <tuple>
#include <compare>
#include <iostream>
struct X {
int i;
auto operator <=>(X const& other) const {
std::cout << this << " <=> " << &other << std::endl;
return i <=> other.i;
}
};
int main() {
std::tuple{X{42}} <=> std::tuple{X{42}};
}
简答:您需要为 X
.
定义 operator==
std::tuple
通过综合三向比较来比较元素,只有当类型满足 std::three_way_comparable_with<T,U>
时才使用 <=>
。最终,这需要 std::three_way_comparable<X>
,这需要一个说明性的 weakly-equality-comparable-with
概念。您可能会猜到,这需要 ==
才有效。
修复是一行:
bool operator==(X const& other) const = default;
既然 <=>
似乎可以独立完成这项工作,为什么还需要 ==
?我只能推测,但这可能是由于概念比我们习惯的更“完整”,例如只需要 operator<
。如果一个类型可以与 <=>
进行比较,那么它实际上也应该支持相等性。
至于为什么<=>
不覆盖==
除非默认,这是因为类的性能缺陷,其等式可以短路(例如向量和字符串)以及任何包含此类类型的 类。没有迹象表明相等比较每个元素而不是短路,所以 <=>
不处理相等,除非它可以保证你会避免这个陷阱(通过默认 <=>
)。
以下代码调用运算符 <=> 两次,参数颠倒。但是为什么?
GCC 10.2 和 clang 12 似乎都在使用 libstdc++-10,它的
#include <tuple>
#include <compare>
#include <iostream>
struct X {
int i;
auto operator <=>(X const& other) const {
std::cout << this << " <=> " << &other << std::endl;
return i <=> other.i;
}
};
int main() {
std::tuple{X{42}} <=> std::tuple{X{42}};
}
简答:您需要为 X
.
operator==
std::tuple
通过综合三向比较来比较元素,只有当类型满足 std::three_way_comparable_with<T,U>
时才使用 <=>
。最终,这需要 std::three_way_comparable<X>
,这需要一个说明性的 weakly-equality-comparable-with
概念。您可能会猜到,这需要 ==
才有效。
修复是一行:
bool operator==(X const& other) const = default;
既然 <=>
似乎可以独立完成这项工作,为什么还需要 ==
?我只能推测,但这可能是由于概念比我们习惯的更“完整”,例如只需要 operator<
。如果一个类型可以与 <=>
进行比较,那么它实际上也应该支持相等性。
至于为什么<=>
不覆盖==
除非默认,这是因为类的性能缺陷,其等式可以短路(例如向量和字符串)以及任何包含此类类型的 类。没有迹象表明相等比较每个元素而不是短路,所以 <=>
不处理相等,除非它可以保证你会避免这个陷阱(通过默认 <=>
)。