为什么 C++20 中的空结构没有隐式宇宙飞船运算符?
Why do empty structs in C++20 do not have implicit spaceship operator?
动机:有时我使用 std::variant 来实现一些枚举状态可以承载状态的“奇特”枚举。
现在,如果我想将 <=>
用于我的变体,它要求我的空结构已定义 <=>。
这对我来说似乎有点奇怪,因为如果类型的状态位为 0,则该类型的所有实例都是相同的。
完整 example:
#include <compare>
#include <iostream>
#include <variant>
struct Off{
// without this the code does not compile
auto operator<=>(const Off& other) const = default;
};
struct Running{
int rpm=1000;
auto operator<=>(const Running& other) const = default;
};
using EngineState = std::variant<Off, Running>;
int main()
{
EngineState es1, es2;
es1<=>es2;
}
默认的比较运算符是选择加入,而不是选择退出。
如果选择退出,那么它可以将无法编译的代码转换为编译后具有某种未知含义的代码。标准委员会尽量保持向后兼容性。
归根结底归结为:一个类型“可比”是什么意思?
可比较的类型首先是带有值的类型。 Objects 此类类型具有某种意义上有意义的值。
你的例子就是这样的一个例子。本质上,您正在使用 variant
和 Off
来增加 Running
的 value-state 和替代值。我自己会使用 optional<Running>
,但无论如何。 Off
是一种在您的问题 space 中合法具有值的类型。它的值是“不是 运行”。
大多数空 object 类型不是这种情况。 std::in_place_t
根据该术语的任何定义都没有有意义的“值”。它是一个标签,用于将 in-place 构造调用分派给某些类型的构造函数。要求将一个实例与另一个实例进行比较是没有意义的。
然而你想让它在默认情况下具有可比性。
有很多 的无状态类型未以value-oriented 方式使用。用于调度重载集的标签、用于提供 object-based 访问全局资源的类型等。这并不是说没有 value-oriented 空类型。但是他们太多了,单方面声明他们都应该默认是可比较的,这似乎很奇怪。
另外,value-oriented是可比性的必要条件,但不单是就足够。对于 明确 value-oriented.
的类型,我们没有默认的可比性
聚合类型拥有所有 public 成员,因此没有什么可以阻止任何人在任何时候将任何值推入其中。他们显然 value-oriented.
然而聚合类型在默认情况下是不可比较的。他们也不应该。并非所有假设可以比较的东西 都应该 进行比较。
即使可以对特定的 collection 值进行排序,允许 对它们进行排序是否有意义?那要看collection了。如果我有 2D 点类型,可以订购。但是应该吗?我可以理解相等性测试,但是 full-on 可比性?你可以定义它,但这样的比较曾经有意义吗?
只有该类型的创建者才能回答这个问题。因此,我们强制类型的创建者要求他们想要什么。
没有成员只是有一些 public 成员的特例。
动机:有时我使用 std::variant 来实现一些枚举状态可以承载状态的“奇特”枚举。
现在,如果我想将 <=>
用于我的变体,它要求我的空结构已定义 <=>。
这对我来说似乎有点奇怪,因为如果类型的状态位为 0,则该类型的所有实例都是相同的。
完整 example:
#include <compare>
#include <iostream>
#include <variant>
struct Off{
// without this the code does not compile
auto operator<=>(const Off& other) const = default;
};
struct Running{
int rpm=1000;
auto operator<=>(const Running& other) const = default;
};
using EngineState = std::variant<Off, Running>;
int main()
{
EngineState es1, es2;
es1<=>es2;
}
默认的比较运算符是选择加入,而不是选择退出。
如果选择退出,那么它可以将无法编译的代码转换为编译后具有某种未知含义的代码。标准委员会尽量保持向后兼容性。
归根结底归结为:一个类型“可比”是什么意思?
可比较的类型首先是带有值的类型。 Objects 此类类型具有某种意义上有意义的值。
你的例子就是这样的一个例子。本质上,您正在使用 variant
和 Off
来增加 Running
的 value-state 和替代值。我自己会使用 optional<Running>
,但无论如何。 Off
是一种在您的问题 space 中合法具有值的类型。它的值是“不是 运行”。
大多数空 object 类型不是这种情况。 std::in_place_t
根据该术语的任何定义都没有有意义的“值”。它是一个标签,用于将 in-place 构造调用分派给某些类型的构造函数。要求将一个实例与另一个实例进行比较是没有意义的。
然而你想让它在默认情况下具有可比性。
有很多 的无状态类型未以value-oriented 方式使用。用于调度重载集的标签、用于提供 object-based 访问全局资源的类型等。这并不是说没有 value-oriented 空类型。但是他们太多了,单方面声明他们都应该默认是可比较的,这似乎很奇怪。
另外,value-oriented是可比性的必要条件,但不单是就足够。对于 明确 value-oriented.
的类型,我们没有默认的可比性聚合类型拥有所有 public 成员,因此没有什么可以阻止任何人在任何时候将任何值推入其中。他们显然 value-oriented.
然而聚合类型在默认情况下是不可比较的。他们也不应该。并非所有假设可以比较的东西 都应该 进行比较。
即使可以对特定的 collection 值进行排序,允许 对它们进行排序是否有意义?那要看collection了。如果我有 2D 点类型,可以订购。但是应该吗?我可以理解相等性测试,但是 full-on 可比性?你可以定义它,但这样的比较曾经有意义吗?
只有该类型的创建者才能回答这个问题。因此,我们强制类型的创建者要求他们想要什么。
没有成员只是有一些 public 成员的特例。