Dan*_*iel 13 c++ language-lawyer
给出以下代码片段:
struct Foo {
};
struct Bar {
operator const Foo() {
return Foo();
}
};
int main() {
Bar bar;
Foo foo(bar);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它可以使用 gcc 11.2 正常编译,但无法使用 clang 12.0 编译,并出现以下错误:
<source>:12:13: error: no viable conversion from 'Bar' to 'Foo'
Foo foo(bar);
^~~
<source>:1:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Bar' to 'const Foo &' for 1st argument
struct Foo {
^
<source>:1:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'Bar' to 'Foo &&' for 1st argument
struct Foo {
^
<source>:5:5: note: candidate function
operator const Foo() {
^
<source>:1:8: note: passing argument to parameter here
struct Foo {
^
Run Code Online (Sandbox Code Playgroud)
PS:我知道它可以通过删除const或返回 const 引用来修复。
我认为这是开放的CWG 问题 2077。
基本上,
Foo foo(bar);
Run Code Online (Sandbox Code Playgroud)
是直接初始化,这意味着它将考虑Foo重载解析的构造函数并选择最佳可行的构造函数。候选人是带有签名的隐式复制和移动构造函数
Foo(const Foo&);
Foo(Foo&&);
Run Code Online (Sandbox Code Playgroud)
如果您查看链接的 CWG 问题并了解相关 Clang bug 的更多详细信息,那么我们会发现这正是那里描述的情况,只是我们的函数调用是构造函数调用,而他们的函数调用是普通函数调用。
如果我们只是相信 CWG 问题中提出的论点,那么重载解析显然应该按照当前规则选择重载Foo&&,而实际上不允许绑定引用,从而导致格式错误的程序。
我将尝试从此处的链接来源重现推理:
当考虑从 转换为构造函数的参数时,由于类型不匹配,bar引用无法直接绑定。bar
根据[over.ics.ref]/2,在这种情况下,转换顺序就像通过引用类型的临时对象的复制初始化来确定。
在这种情况下,转换是Bar -> const Foo -> Foo通过移动构造函数的用户定义构造函数进行的。对于复制构造函数来说是Bar -> const Foo。
然而,在临时的复制初始化中,const 限定符转换被“包含”在初始化中。[over.ics.ref]/2因此,移动构造函数的顺序并不比复制构造函数的顺序差。
在这种情况下,右值引用是决定性因素,因此在重载决策中选择移动构造函数。
但是,aconst Foo不能绑定到非const右值引用。因此该程序是格式错误的。([dcl.init.ref] /5.4.3,DR 1604)
另请注意, [over.ics.ref]的其余部分给出了引用绑定的要求,以影响重载的可行性,但不包括const右值到非const右值引用的绑定。
这在例如复制初始化()中不是问题Foo foo = bar;,因为它可以直接使用转换运算符而无需通过构造函数。
在 C++11 之前这也不是问题,因为那里不存在移动构造函数。
出于同样的原因,如果显式声明 的复制构造函数也不是问题Foo,因为这会禁止声明隐式移动构造函数。
在 C++17 及更高版本中这也不是问题,因为强制复制省略使得移动构造函数永远不会被调用。
我认为这可以解释 Clang 的所有行为。
GCC 和 MSVC 似乎在重载解析中选择复制构造函数而不是移动构造函数,虽然根据标准的当前措辞显然不正确,但可能是预期发生的情况以及链接的 CWG 问题的目标,通过删除来自可行函数集的格式不正确的引用绑定导致函数重载。
| 归档时间: |
|
| 查看次数: |
381 次 |
| 最近记录: |