如以下代码段所示,最近出现了一个兼容问题:
struct Base
{
};
template<typename T>
struct A : Base
{
A(){}
A(Base&&) {}
};
A<int> foo()
{
A<double> v;
return v;
}
int main()
{
auto d = foo();
return 0;
}
Gcc表示还可以,但clang表示不同意,并说“候选构造函数不可行:对于第一个参数A(Base &&){},没有从'A'到'Base &&'的已知转换”,请自己看看:https : //godbolt.org / z / Y7mwnU
任何一种读者都可以通过一些标准语言来支持这两种观点吗?
铛在这里是正确的。提起87530。
返回语句的规则为[class.copy.elision] / 3:
在以下复制初始化上下文中,可以使用移动操作代替复制操作:
- 如果
return
语句([stmt.return])中的表达式是一个(可能带括号的)id表达式,该对象使用在最里面的封闭函数或lambda-expression的主体或参数声明子句中声明的自动存储持续时间来命名对象,要么- 如果throw-expression的操作数是非易失性自动对象(函数或catch子句参数除外)的名称,则其范围不会超出最里面的try块的末尾(如果有) ,
首先执行重载决议为副本选择构造函数,就好像该对象是由右值指定的一样。如果第一个重载解析失败或没有执行,或者所选构造函数的第一个参数的类型不是对该对象类型的右值引用(可能是cv限定),则再次执行重载解析,将对象视为左值。[注意:无论是否出现复制省略,都必须执行此两阶段重载解决方案。如果不执行省略操作,它将确定要调用的构造函数,并且即使取消了调用,所选的构造函数也必须可访问。—尾注]
强调我的。
我们遇到了第一个项目符号,我们返回一个ID表达式,该表达式命名了一个非易失性自动对象。因此,我们执行重载解析,就好像它是一个右值一样。此重载解析成功,有一个采用的构造函数Base&&
。但是,请注意粗体部分。此参数的类型不是对该对象类型的右值引用。
因此,我们再次尝试将对象视为左值。此重载解决方案失败。
结果,程序格式不正确。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句