(x != x) 默认相等运算符==

问题描述 投票:0回答:1

这个节目

struct A {
    int i = 0;
    constexpr operator int() const { return i; }
    constexpr operator int&() { return ++i; }
};

struct B {
    A a;
    bool operator==(const B &) const = default;
};

constexpr bool f() {
    B x;
    return x == x;
}

static_assert( f() ); // fails in GCC

在 GCC 编译器中静态断言失败,这意味着

x != x
在持续评估期间是
true
,其中
operator==
由编译器生成。在线演示:https://gcc.godbolt.org/z/4xjTnM54M

如果修改

struct B
使其继承自
A
而不是将其作为字段:

struct B : A {
    bool operator==(const B &) const = default;
};

constexpr bool f() {
    B x;
    return x == x;
}

static_assert( f() ); // fails in Clang

然后程序在 GCC 中成功,但在 Clang 中失败。在线演示:https://gcc.godbolt.org/z/5hYob3K66

两个程序的结构是否良好并且

f()
必须评估为
true

c++ language-lawyer c++20 comparison-operators const-correctness
1个回答
0
投票

这只是 GCC/Clang 中的一个错误。

指定默认的相等运算符,以按声明顺序([class.eq]/3)对其操作数的基类子对象执行成员相等比较,后跟非静态数据成员。

比较是通过

a == b
执行的,其中
a
b
是表示操作数相应子对象的左值。 [class.compare.default]/5 明确表示这样的左值是

由一系列派生到基数的转换、类成员访问表达式和应用于

x

的数组下标表达式组成

其中

x
是默认相等运算符的相应参数,它必然是
const
限定的。

因此,遵循语言的正常规则,

a
b
也应该继承这个
const
限定(引用
mutable
数据成员时除外),但由于某种原因,这在GCC中不会发生非静态数据成员,而 Clang 巧合地在基类子对象上表现出相同的错误行为。

在OP示例中,此错误导致选择

A::operator int&()
而不是
A::operator int() const
来执行内置
A
int
->
operator==(int, int)
转换。

© www.soinside.com 2019 - 2024. All rights reserved.