繁体   English   中英

为什么 spaceship 允许混合比较(不同的模板实例化)与无意义的结果?

[英]Why does spaceship allow mixed comparisons (different template instantiations) with nonsense results?

编辑:这与宇宙飞船无关。 只是使用 spaceship 混淆了我的代码中的真正问题(有关详细信息,请参阅答案)。

我对这个程序的 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:

错误的
错误的
错误的
错误的

在指责 Godbolt 缓存之后......我发现问题在于我正在比较TotallyOrdered<float>TotallyOrdered<double> (在1234.567之后添加f会产生预期的输出)。 我的问题是:

  • 为什么允许这样做? (不问这是否是标准行为;它是,但对设计意图感到好奇。)
  • 为什么比较没有给出strong_ordering中的“枚举”? 尽管我只定义了strong_order <=> ,但当我进行混合比较时,我似乎得到了部分顺序。
  • 如何强制仅“精确 +-cvref”比较(给出std::strong_ordering结果)编译,防止给出std::partial_ordering的比较?

这是允许的,因为您到T的转换运算符不明确。 这允许比较的双方进行用户定义的转换为各自的T 所以你最终得到一个float和一个double 然后它们都可以转换为double并且可以进行比较。 但该比较返回std::partial_ordering ,而不是std::strong_ordering

请注意, std::strong_ordering可以与 bool 进行比较,这就是您的代码首先编译的原因。 虽然 cppreference.com 确实注意到:

尝试将 strong_ordering 与 integer 文字 0 以外的任何内容进行比较的程序的行为未定义。

我不是 100% 确定您的程序是否正在显示未定义的行为,或者是否有更多的转换/促销“魔术”正在进行。

无论哪种方式,如果您将转换运算符更改为显式,代码将不再编译。 我猜这是你真正想要的?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM