HC4*_*ica 17 c++ gcc clang overload-resolution c++11
GCC(使用4.9测试)接受以下测试用例:
struct Base {};
struct Derived : Base {
Derived();
explicit Derived(const Derived&);
explicit Derived(Derived&&);
explicit Derived(const Base&);
Derived(Base&&);
};
Derived foo() {
Derived result;
return result;
}
int main() {
Derived result = foo();
}
Run Code Online (Sandbox Code Playgroud)
Clang(使用3.5测试)拒绝它,并显示以下错误消息:
test.cpp:13:10: error: no matching constructor for initialization of 'Derived'
return result;
^~~~~~
test.cpp:8:5: note: candidate constructor not viable: no known conversion from 'Derived' to 'Base &&' for 1st argument
Derived(Base&&);
^
test.cpp:4:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
Derived();
^
Run Code Online (Sandbox Code Playgroud)
谁是对的?
HC4*_*ica 14
我相信Clang在这里是正确的.海湾合作委员会不应接受该守则.
原因是return在[class.copy] p32(强调我的)中指定了语句中发生的对象副本的构造函数的重载解析:
当满足复制/移动构造函数的省略标准时,[...]和要复制的对象由左值,[...]指定,首先执行重载的选择构造函数的重载决策好像对象是由右值指定的.如果第一个重载决策失败或未执行,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv-qualified),则再次执行重载决策,将对象视为左值.
在此示例中,符合elision的条件(通过第一个项目符号[class.copy] p31),并且要复制的对象由左值指定,因此本段适用.
首先尝试重载分辨率,就像对象由右值指定一样.该explicit构造函数不是候选人(见下文的原因的解释),所以Derived(Base&&)被选择的构造.但是,这属于"所选构造函数的第一个参数的类型不是对象类型的右值引用"(相反,它是对象基类类型的右值引用),因此应该再次执行重载决策,将对象视为左值.
第二个重载决策失败,因为唯一可行的构造函数(同样,explicit构造函数不是候选者)具有rvalue引用参数,该参数不能绑定到左值.Clang显示导致的重载决策失败错误.
为了完成解释,这就是为什么explicit构造函数不适合重载解析(所有重点都是我的).
首先,[dcl.init] p15说:
初始化发生在一个 括号或等于初始值或条件(6.4)的形式,以及参数传递,函数返回,抛出异常(15.1),处理异常(15.3)和聚合成员初始化(8.5.1),称为复制初始化."
接下来,我们来看看[over.match.ctor] p1:
对于复制初始化,候选函数是该类的所有转换构造函数(12.3.1).
最后,我们看到explicit构造函数没有转换构造函数[class.conv.ctor] p1:
声明没有函数说明
explicit符的构造函数指定从其参数类型到其类类型的转换.这样的构造函数称为转换构造函数.
| 归档时间: |
|
| 查看次数: |
213 次 |
| 最近记录: |