【问题标题】:Trying to use spaceship operator in derived classes尝试在派生类中使用宇宙飞船运算符
【发布时间】:2020-09-28 10:09:47
【问题描述】:

我正在尝试在基类中使用宇宙飞船运算符,因此我将通过编译器定义所有运算符。 (来源:https://devblogs.microsoft.com/cppblog/simplify-your-code-with-rocket-science-c20s-spaceship-operator/

但是我遇到了我不明白的问题。

源代码:https://godbolt.org/z/SZnNfK

#include <chrono>
#include <cassert>
#include <iostream>

#define USE_SPACESHIP

class ITimestampWrapper
{
public:
    ITimestampWrapper() noexcept
        : _timestamp(std::chrono::steady_clock::now())
    {

    }

    explicit ITimestampWrapper(std::chrono::steady_clock::time_point timestamp) noexcept
        : _timestamp(timestamp)
    {

    }

#ifndef USE_SPACESHIP
    friend bool operator<(const ITimestampWrapper& lhs, const ITimestampWrapper& rhs)
    {
        return lhs._timestamp < rhs._timestamp;
    }

    friend bool operator>(const ITimestampWrapper& lhs, const ITimestampWrapper& rhs)
    {
        return lhs._timestamp > rhs._timestamp;
    }
#else
    friend auto operator<=>(const ITimestampWrapper&, const ITimestampWrapper&) = default;
#endif

    virtual ~ITimestampWrapper() = default;

private:
    std::chrono::steady_clock::time_point _timestamp;
};

class testClass : public ITimestampWrapper
{
public:
    testClass() = default;

    explicit testClass(std::chrono::steady_clock::time_point test)
        : ITimestampWrapper(test)
    {

    }

    int _x = 0;
};


class testClass2 : public ITimestampWrapper
{
public:
    testClass2() = default;

    explicit testClass2(std::chrono::steady_clock::time_point test)
        : ITimestampWrapper(test)
    {

    }

    int _x = 0;
};

int main()
{
    auto testTime = std::chrono::steady_clock::now();

    testClass A;
    A._x = 50000;


    testClass B(testTime);
    B._x = 6000;

    if(A > B)
    {
        std::cout << "Correct A is older than B" << std::endl;
    }
    else
    {
        std::cout << "Wrong A is older than B" << std::endl;
    }

    auto testTime2 = std::chrono::steady_clock::now();

    testClass AA;
    AA._x = 50000;


    testClass2 BB(testTime2);
    BB._x = 6000;

    if(AA > BB)
    {
        std::cout << "Correct AA is older than BB" << std::endl;
    }
    else
    {
        std::cout << "Wrong AA is older than BB" << std::endl;
    }
}

输出:

使用 USE_SPACESHIP:

正确的 A 早于 B

错误的 AA 不比 BB 旧 //

没有使用太空船:

正确的 A 早于 B

正确的 AA 早于 BB

当我自己在基类中实现运算符 时,即使我在比较具有相同基类的不同类时,比较仍然有效。

但是当我使用 spaceship 运算符时,只有在应用于具有相同基数的相同 ClassType 时,比较才有效。

这两种方法有何不同?

注意:我只想比较基类的时间戳,而不是基类或派生类的任何其他成员

取消定义使用经典运算符重载的 USE_SPACESHIP 宏

谢谢。

编辑:我尝试使用 CRTP 方法,但遇到了同样的问题。

【问题讨论】:

  • 看起来像一个编译器错误,但我不确定。如果你去掉-O3,它似乎工作正常。
  • 嗯,我们在项目中使用了-O2,所以这绝对是一个编译器错误。有没有办法向 C++ 开发人员报告这个问题?
  • 可以肯定这是一个错误。直接使用&lt;=&gt; 来完成编译器的“as-if”工作,即使经过优化,也会产生正确的结果。您似乎正在使用 GCC,因此应该报告 GCC bugzilla

标签: c++ c++20 spaceship-operator


【解决方案1】:

我想这是 GCC 的一个错误。正如你在这个程序集中看到的here

    mov     eax, OFFSET FLAT:vtable for testClass+16
    cmp     rax, OFFSET FLAT:vtable for testClass2+16

gcc 比较 vtable 的成员:它比较的是 AA 的静态类型和 BB 的静态类型,而不是时间戳。

【讨论】:

    【解决方案2】:

    如果您省略 -O3 或如果您提供 -O0,它会起作用。 -O1-O2 也失败了。看起来像是编译器错误(或某处未定义的行为)。

    【讨论】:

      猜你喜欢
      • 2011-03-04
      • 2010-10-24
      • 2021-08-07
      • 1970-01-01
      • 2021-07-27
      • 2011-01-30
      • 1970-01-01
      • 2010-11-25
      相关资源
      最近更新 更多