为啥允许将 std::optional 与值进行比较? [复制]

Posted

技术标签:

【中文标题】为啥允许将 std::optional 与值进行比较? [复制]【英文标题】:Why std::optional is allowed to be compared to value? [duplicate]为什么允许将 std::optional 与值进行比较? [复制] 【发布时间】:2021-07-23 00:48:03 【问题描述】:

能够比较std::optional<T>T 的相等性非常有用:

std::optional<int> opt_value;
int value = 123;

opt_value == value; // will always be 'false'

我认为这种情况下的行为定义明确且清晰。

我不明白为什么允许这样做:

opt_value < value; // this will always be 'true'

我期待这甚至无法编译。 我认为这里发生的事情非常模糊。 STL 中添加了这个的原因是什么?

【问题讨论】:

@JDługosz 正如我所说,我希望它甚至无法编译 这样你就可以拥有一个std::optional的容器,并对其进行排序。或者在需要订购时使用std::optional @JDługosz 确切地说,我认为使nullopt 总是小于任何其他值是完全任意的。由于许多这些不明显的默认行为通常不会进入标准,我想知道为什么这个特定的行为可以代替。 我不明白是什么让opt_value == value(对于支持operator== 的值类型比opt_value &lt; value(对于支持operator&lt; 的值类型)在语义上更有意义),可能的例外是感觉比nullopt_t != value 更“明显”,而 null 可选值和实际值的顺序并不是那么直观。但是“空可选值小于所有值”在 imo 中并不奇怪。 @nyarlathotep108:“是一种非常隐晦的晦涩行为。”我不同意。如果要比较未参与的optional&lt;T&gt;,则只有两个答案:小于所有Ts,或大于所有Ts。 【参考方案1】:

简答:map&lt;optional&lt;int&gt;, int&gt;T 可用作键时,您希望能够将optional&lt;T&gt; 用作map 键。将 empty 状态定义为小于或大于正常值使其表现良好。

同时,比较一个普通的 T 和一个 optional&lt;T&gt; 应该只是,从逻辑上讲,将纯 T 升级为一个 optional&lt;T&gt; 持有该值。因此,提供一个采用裸 T 的重载表单只是一种优化,应该具有相同的结果。

【讨论】:

当可选是关键时,他们可以为容器提供默认的比较功能,而无需使用全局运算符 【参考方案2】:

本质上,它可以让您更轻松地比较值。有了这个你就不用写了:

opt_value.value() < value;

它还会检查以确保 opt_value 具有值。

【讨论】:

我知道这很实用,但我更愿意在这种情况下写更多。这就是重点:在大多数情况下,我更喜欢显式而不是隐式,除非行为非常明显。【参考方案3】:

介绍optional to C++ states the conceptual idea of the type的提案。 optional&lt;T&gt; 是一个对象,它增加了对象类型T 一个附加值:nullopt。这就是类型的想法;这是一个T,可以有一个额外的值。

鉴于此推理,如果订购了T,那么也应该订购optional&lt;T&gt;。所以现在的问题不是是否应该做到这一点,而是如何做到这一点。

该答案是任意的,但只有两个合理的答案:“不是T”小于T 的所有值,或者大于T 的所有值。他们选择了前者。

【讨论】:

听起来像是一个武断的决定。我宁愿不为类型定义任意运算符 这也是任意的,但这是 C 的遗产(strcmp 已经存在,所以它是有道理的)。也许本世纪我们可以做得更好。 当然,对于绝大多数可选到可选的比较,它根本不是任意的,因为它遵循值类型的底层比较。是否应该仅仅因为 nullopt_t 小于 0 而不是大于或不可比 0 有点武断而牺牲所有这些? 奇怪的是nullopt 小于INT_MIN。我确实同意能够比较事物是有价值的,但是一个命名的比较器(optional_cmp?)会有用处,并且不会破坏人们的期望(你会知道你在注册什么)。 这对我来说并不奇怪。 INT_MIN 小于所有其他 ints,但我们预计它不会小于 LONG_MIN-DBL_MAX。是最小的int,不是最小的std::optional&lt;int&gt;或其他类型。

以上是关于为啥允许将 std::optional 与值进行比较? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 std::optional 不允许“移动构造和仅复制分配”类型的移动分配?

为啥 std::optional 构造函数使用 std::in_place?

为啥 std::optional::value() &&;返回 &&?

`std::optional` 比 `std::shared_ptr` 和 `std::unique_ptr` 有啥优势?

为啥 const rvalue 限定 std::optional::value() 返回 const rvalue 引用?

为啥 std::optional 对 std::nullopt 类型的操作数有一个特殊的相等运算符