为什么太空飞船允许混合比较(不同的模板实例化)和无意义的结果?

无意义

编辑:这与飞船无关。只是太空飞船的使用使我的代码中的真正问题变得模糊(请参阅答案以了解详细信息)。

我对该程序的输出感到惊讶:(如果您喜欢拼图,请随时打开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;
}

输出:

假的
假的
假的
假的

经过一番责怪Godbolt缓存之后,我发现问题出在,我正在比较TotallyOrdered<float>TotallyOrdered<double>(添加f1234.567给出了预期的输出)。我的问题是:

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

之所以允许,是因为您的转化运算符toT不明确。这样可以使比较的两面都经过用户定义的转换为各自的T因此,您最终得到afloat和a double然后可以将它们都转换为double可以进行比较。但是该比较返回std::partial_ordering,而不是std::strong_ordering

请注意,std::strong_ordering可以将其与bool进行比较,这就是为什么您的代码首先要编译的原因。尽管cppreference.com确实指出:

试图将strong_ordering与整数文字``0''以外的任何东西进行比较的程序的行为是未定义的。

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

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如果字段和方法是静态的,为什么新建一个类的实例毫无意义/毫无意义?[C#]

无意义 length() 结果

为什么在模板实例化中不允许使用lambda?

在可以区分比较和模板实例化之前,C ++解析器会做什么?

为什么C ++模板实例化失败?

为什么以下代码导致模板实例化?

为什么要在宏中使用看似毫无意义的do-while和if-else语句?

Prolog和无意义的含义

标志=无意义?

为什么“二进制访问在UNIX系统上毫无意义”?

为什么“从不”类型在联合类型中毫无意义?

CSource筛选器上的SetMediaTime使输出AVI无意义-知道为什么吗?

总结为什么 keras 自定义层会产生无意义的输出形状

为什么Valac用C代码生成这些(无意义的)临时指针

为什么 GetProcessHeap 在 Windows 10 上返回一个无意义的句柄?

模板实例化

在不同文件中模板化模板实例化

Prolog如何得出无意义的结果,例如3 <2?

C ++解析器如何区分比较和模板实例化?

CIFAR-10无意义的标准化值

使用“getchar()”和“EOF”期间的无意义输出流

为什么显式模板实例化不会破坏ODR?

通过typedef template <typename T,T>强制模板实例化-为什么有效?

为什么模板实例化在这里永远存在?

为什么我的可变参数模板实例化不起作用?

为什么我的太空飞船不指向地球?

GCC中的模板实例化与Visual C ++不同

为什么在这个例子中使用 Bean - 它看起来像毫无意义的间接?

为什么从float隐式转换为double会在我的程序中返回一个无意义的数字?