gpt4 book ai didi

C++20 行为用相等运算符破坏现有代码?

转载 作者:行者123 更新时间:2023-12-03 10:01:47 25 4
gpt4 key购买 nike

我在调试时遇到了这个问题 this question .
我一直将其修剪为仅使用 Boost Operators :

  • 编译器资源管理器 C++17 C++20
    #include <boost/operators.hpp>

    struct F : boost::totally_ordered1<F, boost::totally_ordered2<F, int>> {
    /*implicit*/ F(int t_) : t(t_) {}
    bool operator==(F const& o) const { return t == o.t; }
    bool operator< (F const& o) const { return t < o.t; }
    private: int t;
    };

    int main() {
    #pragma GCC diagnostic ignored "-Wunused"
    F { 42 } == F{ 42 }; // OKAY
    42 == F{42}; // C++17 OK, C++20 infinite recursion
    F { 42 } == 42; // C++17 OK, C++20 infinite recursion
    }
    该程序在 GCC 和 Clang 中使用 C++17(启用 ubsan/asan)编译并运行良好。
  • 当您将隐式构造函数更改为 explicit 时,问题线路明显 no longer compile on C++17

  • 令人惊讶的是两个版本 在 C++20 上编译(v1v2) ,但它们会导致 无限递归 (崩溃或紧密循环,取决于优化级别)在 C++17 上无法编译的两行。
    显然,这种通过升级到 C++20 而潜入的无声错误令人担忧。
    问题:
  • 这是否符合 c++20 行为(我希望如此)
  • 究竟是什么干扰?我怀疑这可能是由于 c++20 的新“飞船运算符(operator)”支持,但不明白 怎么样它改变了这段代码的行为。
  • 最佳答案

    事实上,不幸的是,C++20 使这段代码无限递归。
    这是一个简化的示例:

    struct F {
    /*implicit*/ F(int t_) : t(t_) {}

    // member: #1
    bool operator==(F const& o) const { return t == o.t; }

    // non-member: #2
    friend bool operator==(const int& y, const F& x) { return x == y; }

    private:
    int t;
    };
    我们看看 42 == F{42} .
    在 C++17 中,我们只有一个候选者:非成员候选者 ( #2 ),所以我们选择了它。它的 body , x == y ,本身只有一个候选人:成员候选人( #1 ),它涉及隐式转换 yF .然后该成员候选人比较两个整数成员,这完全没问题。
    在 C++20 中,初始表达式 42 == F{42}现在有两个候选人:与以前一样的非成员候选人( #2 ),现在还有反向成员候选人( #1 反向)。 #2是更好的匹配 - 我们完全匹配两个参数而不是调用转换,所以它被选中。
    然而现在, x == y现在有两个候选人:再次是成员候选人( #1 ),还有反向非成员候选人( #2 反向)。 #2再次是更好的匹配,原因与之前它是更好的匹配相同:不需要转换。所以我们评估 y == x相反。无限递归。
    非逆转候选人比逆转候选人更受欢迎,但只能作为决胜局。更好的转换顺序永远是第一位的。

    好的,太好了,我们该如何解决?最简单的选择是完全删除非成员候选人:
    struct F {
    /*implicit*/ F(int t_) : t(t_) {}

    bool operator==(F const& o) const { return t == o.t; }

    private:
    int t;
    };
    42 == F{42}这里评估为 F{42}.operator==(42) ,这工作正常。
    如果我们想保留非成员候选人,我们可以明确添加其反向候选人:
    struct F {
    /*implicit*/ F(int t_) : t(t_) {}
    bool operator==(F const& o) const { return t == o.t; }
    bool operator==(int i) const { return t == i; }
    friend bool operator==(const int& y, const F& x) { return x == y; }

    private:
    int t;
    };
    这使得 42 == F{42}仍然选择非成员(member)候选人,但现在 x == y在正文中,将更喜欢成员候选人,然后进行正常的平等。
    最后一个版本还可以删除非成员候选人。以下也适用于所有测试用例,无需递归(这也是我在 C++20 中编写比较的方式):
    struct F {
    /*implicit*/ F(int t_) : t(t_) {}
    bool operator==(F const& o) const { return t == o.t; }
    bool operator==(int i) const { return t == i; }

    private:
    int t;
    };

    关于C++20 行为用相等运算符破坏现有代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65648897/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com