Koz*_*mar 6 c++ clang rvalue-reference move-semantics c++17
下面的代码:
#include <iostream>
struct A {
A() { std::cout << "()" << std::endl; }
A(A&&) { std::cout << "(A&&)" << std::endl; }
A(const A&) { std::cout << "(const A&)" << std::endl; }
};
A fun (A&& a){
return a;
}
int main(){
A a;
fun(std::move(a));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在 clang 16.0.3 (arm64-apple-darwin22.4.0 和 c++17) 中产生
()
(A&&)
Run Code Online (Sandbox Code Playgroud)
虽然大多数编译器给出
()
(const A&)
Run Code Online (Sandbox Code Playgroud)
哪一个是正确的?
A::A(A&&)由于按值返回时局部变量和参数的隐式移动规则,因此应在此处使用移动构造函数:
如果表达式是一个(可能带括号的)id 表达式,它命名一个变量,该变量的类型是
非易失性对象类型或
对对象类型的非易失性右值引用 (C++20 起)
并且声明了该变量
在体内或
作为参数
最里面的封闭函数或 lambda 表达式,
然后执行两次重载解析以选择用于初始化返回值的构造函数,或者对于 co_return,选择 Promise.return_value() (C++20 起) 的重载:
- 首先,就好像表达式是一个右值表达式(因此它可以选择移动构造函数),并且
- 如果第一个重载决议失败或者
- 它成功了,但没有选择移动构造函数(正式地,所选构造函数的第一个参数不是对(可能是 cv 限定的)表达式类型的右值引用)(C++20 之前)
- 然后像往常一样执行重载决策,并将表达式视为左值(因此它可以选择复制构造函数)。
(强调我的)
在您的示例中,您有语句return a;并且a是最内层封闭函数的参数,因此重载解析可以执行两次。在第一步中a,将其视为右值表达式,因此可以在此处使用移动构造函数。
请注意,由于第一步已成功,因此无需执行第二步。