复制赋值运算符的重载解决方案

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

如果除了隐式定义的复制赋值运算符之外,类还定义了不带左值引用对象参数的

operator =
,则必须选择哪个运算符?

请考虑以下示例,其中包含两个结构,每个结构都具有重载的复制赋值运算符:

struct A {
    int operator =(this const A &, const A&) { return 1; }
    operator int() const { return 2; }
};

struct B {
    int operator =(this volatile B &, const B&) { return 1; }
    operator int() const { return 2; }
};

template<typename T>
int f(T t) {
    return t = T{};
}

int main() {
    return 10 * f(A{}) + f(B{});
}

程序返回两位数。如果在

1
中选择了用户定义的
operator =
,第一位数字为
A a; a = A{};
;如果选择隐式定义的复制赋值运算符,第一位数字为
2
。第二个数字类似地显示选择,但对于
B b; b = B{};
,当前编译器不同意程序的返回值。

Clang 返回

11
意味着用户定义的运算符都优于隐式定义的复制赋值运算符。

MSVC 返回

22
始终选择隐式定义的复制赋值运算符而不是用户的复制赋值运算符。

GCC 位于中间,返回值

21
。在线演示:https://gcc.godbolt.org/z/d4hbe7cn8

这里哪个编译器是正确的?

c++ language-lawyer assignment-operator c++23 explicit-object-parameter
1个回答
0
投票

Clang 是正确的,其他都不是。

您声明的两个赋值运算符都是复制赋值运算符 [class.copy.assign]/1:

用户声明的 copy 赋值运算符 X::operator= 是类 X 的非静态非模板成员函数,只有一个类型为 X、X&、const X&、易失性 X& 或的非对象参数const 易失性 X&.

在两个

operator=
声明中,第一个参数是显式对象参数(因为
this
),即对象参数,因此不计入复制赋值运算符的确定中。

因此,编译器不得隐式声明任何复制或移动赋值运算符。

在重载决策中没有可以选择的隐式重载。

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