从右值引用到base的构造函数 - 可行(gcc)或不(clang) - 谁是对的

Łuk*_*ski 7 c++ gcc return clang language-lawyer

最近有一个恭维问题,由此片段说明:

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;
}
Run Code Online (Sandbox Code Playgroud)

Gcc说没关系,但是clang不同意并说"候选构造函数不可行:第一个参数A(Base &&){}"没有已知的从'A'到'Base &&'的转换,请亲自看看:https://godbolt.org/Z/Y7mwnU

任何一种读者是否能够帮助支持任何一种观点?

Bar*_*rry 3

clang在这里是正确的。提交87530

\n

return 语句的规则是[class.copy.elision]/3

\n
\n

在以下复制初始化上下文中,可能会使用移动操作而不是复制操作:

\n
    \n
  • 如果语句return([stmt.return]) 中的表达式是一个(可能带括号的)id 表达式,它命名一个对象,该对象具有在最内层封闭函数或lambda 表达式的主体或参数声明子句中声明的自动存储持续时间,或者
  • \n
  • 如果throw 表达式的操作数是非易失性自动对象的名称(函数或catch 子句参数除外)除外),其范围不超出最内层封闭 try 块的末尾(如果有一个) ,
  • \n
\n

首先执行重载决策来选择副本的构造函数,就好像该对象是由右值指定的一样。如果第一个重载决策失败或未执行,或者所选构造函数的第一个参数的类型不是对象类型的右值引用(可能是 cv 限定的),则再次执行重载决策,同时考虑对象作为左值。[\xe2\x80\x89注意:无论是否发生复制省略,都必须执行此两阶段重载决策。如果不执行省略,它确定要调用的构造函数,并且即使省略调用,所选构造函数也必须可访问。\xe2\x80\x94\xe2\x80\x89尾注\xe2\x80\x89]

\n
\n

强调我的。

\n

我们遇到了第一点,我们返回一个命名非易失性自动对象的id 表达式。因此,我们将重载解析视为右值。此重载解析成功,有一个构造函数采用Base&&. 不过,请注意粗体部分。该参数的类型不是类型的右值引用。

\n

因此,我们再次尝试将该对象视为左值。此重载决策失败。

\n

因此,该程序格式不正确。

\n