[英]Why does spaceship allow mixed comparisons (different template instantiations) with nonsense results?
EDIT: This has nothing to do with spaceship.编辑:这与宇宙飞船无关。 It is just that the use of spaceship obfuscated the real issue in my code (see answer for details).
只是使用 spaceship 混淆了我的代码中的真正问题(有关详细信息,请参阅答案)。
I was surprised by the output of this program : (If you like puzzles feel free to open the Godbolt link and try to spot the cause yourself)我对这个程序的 output 感到惊讶:(如果您喜欢谜题,请随时打开 Godbolt 链接并尝试自己找出原因)
#include <cstdint>
#include <cassert>
#include <compare>
#include <cmath>
#include <iostream>
#include <limits>
template<typename T>
struct TotallyOrdered
{
T val;
constexpr TotallyOrdered(T val) :
val(val) {}
constexpr operator T() const { return val; }
constexpr std::strong_ordering operator<=>(TotallyOrdered const& other) const
{
if (std::isnan(val) && std::isnan(other.val))
{
return std::strong_ordering::equal;
}
if (std::isnan(val))
{
return std::strong_ordering::less;
}
if (std::isnan(other.val))
{
return std::strong_ordering::greater;
}
if (val < other.val)
{
return std::strong_ordering::less;
}
else if (val == other.val)
{
return std::strong_ordering::equal;
}
else
{
assert(val > other.val);
return std::strong_ordering::greater;
}
}
};
int main()
{
const auto qNan = std::numeric_limits<float>::quiet_NaN();
std::cout << std::boolalpha;
std::cout << ((TotallyOrdered{qNan} <=> TotallyOrdered{1234.567}) == std::strong_ordering::less) << std::endl;
std::cout << ((TotallyOrdered{qNan} <=> TotallyOrdered{1234.567}) == std::strong_ordering::equal) << std::endl;
std::cout << ((TotallyOrdered{qNan} <=> TotallyOrdered{1234.567}) == std::strong_ordering::equivalent) << std::endl;
std::cout << ((TotallyOrdered{qNan} <=> TotallyOrdered{1234.567}) == std::strong_ordering::greater) << std::endl;
}
output: output:
false
错误的
false错误的
false错误的
false错误的
After a bit of blaming Godbolt caching... I have figured out that the problem is that I was comparing TotallyOrdered<float>
and TotallyOrdered<double>
(adding f
after 1234.567
gives expected output).在指责 Godbolt 缓存之后......我发现问题在于我正在比较
TotallyOrdered<float>
和TotallyOrdered<double>
(在1234.567
之后添加f
会产生预期的输出)。 My questions are:我的问题是:
strong_order
<=>
.strong_order
<=>
,但当我进行混合比较时,我似乎得到了部分顺序。std::strong_ordering
result) compile, preventing comparisons that give std::partial_ordering
?std::strong_ordering
结果)编译,防止给出std::partial_ordering
的比较? It's allowed because your conversion operator to T
is not explicit.这是允许的,因为您到
T
的转换运算符不明确。 This allows both sides of the comparison to undergo a user-defined conversion to their respective T
.这允许比较的双方进行用户定义的转换为各自的
T
。 So you end up with a float
and a double
.所以你最终得到一个
float
和一个double
。 And then those can both be converted to double
and a comparison can happen.然后它们都可以转换为
double
并且可以进行比较。 But that comparison returns an std::partial_ordering
, not an std::strong_ordering
.但该比较返回
std::partial_ordering
,而不是std::strong_ordering
。
Note that std::strong_ordering
can be compared to a bool, which is why your code compiles in the first place.请注意,
std::strong_ordering
可以与 bool 进行比较,这就是您的代码首先编译的原因。 Although cppreference.com does note that:虽然 cppreference.com 确实注意到:
The behavior of a program that attempts to compare a strong_ordering with anything other than the integer literal 0 is undefined.
尝试将 strong_ordering 与 integer 文字 0 以外的任何内容进行比较的程序的行为未定义。
I'm not a 100% sure whether your program is displaying undefined behavior, or whether there's some more conversion/promotion "magic" going on.我不是 100% 确定您的程序是否正在显示未定义的行为,或者是否有更多的转换/促销“魔术”正在进行。
Either way, if you change your conversion operator to be explicit, the code won't compile anymore.无论哪种方式,如果您将转换运算符更改为显式,代码将不再编译。 Which I guess is what you actually want?
我猜这是你真正想要的?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.