提问人:Enlico 提问时间:3/10/2023 最后编辑:Enlico 更新时间:3/18/2023 访问量:86
对于用户定义类型,是否禁止对用户定义 operator= 的 lhs 使用转换运算符?如果是这样,标准中的哪一部分禁止它?
Is the use of conversion operator forbidden for the lhs of user-defined operator= for user-defined types? If so, what part of the standars forbids it?
问:
以一个简单的类为例,包装一个 ,int
struct Foo {
int x;
} f;
以及一个包含 和 可以转换为它的类,Foo
struct Bar {
Foo f;
operator Foo&() {
return f;
}
operator Foo const&() const {
return f;
}
Bar& operator=(Bar const&) = default;
} b;
标准的哪一部分(如果有的话)使它无效
b = f;
而不是等同于这个?
static_cast<Foo&>(b) = f;
(我不是说它应该,也不是说它会是正常的、预期的或类似的东西。
这里我读到了
对于内置赋值运算符,左操作数的转换受到如下限制:
- [...]
- 不会对左操作数应用任何用户定义的转换,以实现与内置候选项的最左侧参数的类型匹配。
对于所有其他运营商,此类限制不适用。
那么我是否误解了“内置赋值运算符”的含义,而 in 是适用该限制的内置函数?=
b = f
=
或者这不是 bult-in,因此限制不适用,但代码由于其他原因存在缺陷?=
答:
您正在考虑的复制赋值运算符不是“内置”运算符,但将操作数转换为重载运算符也受到限制,如下所示:
转换为隐式对象参数或转换为赋值操作的左操作数时,仅允许使用标准转换序列。
https://eel.is/c++draft/over.best.ics#general-9
本说明中也提到了这一点
注 1:由于在转换为赋值操作 ([over.best.ics]) 的左操作数时仅考虑标准转换序列,因此具有类类型的子表达式的表达式始终被解释为 。
x = y
x
x.operator=(y)
https://eel.is/c++draft/over.oper#over.ass-note-1
第 3 段描述了候选集:
- 对于操作数类型为 cv1 T1 的一元运算符 @,以及左操作数为 cv1 T1 且右操作数类型为 cv2 T2 的二元运算符 @,四组候选函数、指定成员候选函数、非成员候选函数、内置候选函数和重写候选函数构造如下:
- 如果 是完整的类类型或当前正在定义的类,则成员候选集是在 的作用域中搜索的结果;否则,成员候选项集为空。
T1
operator@
T1
- 对于运算符 、 或 ,非成员候选项的集合为空;否则 [...]
=
[]
->
因此,对于,我们的会员候选人是,我们没有非会员候选人。b = f
b.operator=(f)
您引用的段落谈到了内置候选者何时可行,但内置的候选项是由语言提供的(在 [over.built] 中)——如果您的类型可转换为类似 .这些在这里无关紧要。int&
但在这种情况下,可以转换为 ,并且这里没有可以考虑作为候选的机制。我们只有成员候选人要考虑,而且只有我们自己的(的)成员 - 而不是任意其他类型的成员。b
Foo&
Foo::operator=
Bar
上一个:算子重载的基本规则和习语是什么?
评论
Foo& Foo::operator=(const Foo&)
b = f;
Bar(Foo const& foo) : f{foo} {}