结构化绑定是否应作为 C++20 中的右值从函数返回?
考虑一个 C++20 程序,其中函数中foo有一个结构化绑定auto [y]。函数返回y,它被转换为对象类型A。A可以从右值引用的常量引用构造。
#include <tuple>
#include <iostream>
struct A {
A(const int &) { std::cout << "A(const int &) "; }
A(int &&) { std::cout << "A(int &&) "; }
};
A foo() {
auto [y] = std::make_tuple(1);
return y;
}
int main() { foo(); }
根据C++20语言标准应该选择哪一个构造函数?
Clang 选择A(const int &)和 GCC 选择A(int &&),演示:https : //gcc.godbolt.org/z/5q779vE6T
是否有一个编译器不支持这方面的标准?
回答
我相信 Clang 是正确的。
TL;DR:一些左值可以隐式移动,但结构化绑定不是这样的左值。
- 结构化绑定的名称是左值:
[dcl.struct.bind]/1 :
[dcl.struct.bind]/4 :
- 如果变量名(通常是左值)
return命名为隐式可移动实体,则它可以在语句中移动:
- 如果表达的
return([stmt.return])或co_return([stmt.return.coroutine])语句是一个(可能是括号)ID-表达名称隐式可动实体主体或声明参数声明子句的最里面的封闭函数或lambda 表达式,或- [...]
- 从隐式可移动实体的定义中可以看出,只有对象和(右值)引用可以隐式移动。但结构化绑定两者都不是。
[基本.pre]/3 :
所以我相信结构化绑定不能被隐式移动。
如果y是一个对象或引用,那么它将在return y;.
编辑:编写的 C++17 指定元组成员的结构化绑定是引用。这已由CWG 2313纠正。