在 C++20 中,结构化绑定是否应该作为右值从函数返回?
Shall structured binding be returned from a function as rvalue in C++20?
考虑一个 C++20 程序,其中在函数 foo
中有一个结构化绑定 auto [y]
。函数 returns y
,转换为 A
类型的对象。 A
可以从右值引用的 const 引用构造。
#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:一些左值可以隐式移动,但结构化绑定不是这样的左值。
- 结构化绑定的名称是左值:
A structured binding declaration introduces the identifiers v<sub>0</sub>
, v<sub>1</sub>
, v<sub>2</sub>
,… of the identifier-list as names of structured bindings.
Each v<sub>i</sub>
is the name of an lvalue of type T<sub>i</sub>
that refers to the object bound to r<sub>i</sub>
; the referenced type is r<sub>i</sub>
.
- 变量名(通常是左值)可以在
return
语句中移动,如果它命名为 隐式移动实体 :
An implicitly movable entity is a variable of automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type.
In the following copy-initialization contexts, a move operation is first considered before attempting a copy operation:
- If the expression in a
return
([stmt.return]) or co_return
([stmt.return.coroutine]) statement is a (possibly parenthesized) id-expression that names an implicitly movable entity declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, or
- [...]
- 从隐式移动实体的定义可以看出,只能隐式移动对象和(右值)引用。但是结构化绑定两者都不是。
An entity is a value, object, reference, [or] structured binding[...].
所以我认为不能隐式移动结构化绑定。
如果 y
是对象或引用,那么它将在 return y;
中隐式移动。
编辑:C++17 规定元组成员的结构化绑定是引用。 CWG 2313.
对此进行了更正
考虑一个 C++20 程序,其中在函数 foo
中有一个结构化绑定 auto [y]
。函数 returns y
,转换为 A
类型的对象。 A
可以从右值引用的 const 引用构造。
#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:一些左值可以隐式移动,但结构化绑定不是这样的左值。
- 结构化绑定的名称是左值:
A structured binding declaration introduces the identifiers
v<sub>0</sub>
,v<sub>1</sub>
,v<sub>2</sub>
,… of the identifier-list as names of structured bindings.
Each
v<sub>i</sub>
is the name of an lvalue of typeT<sub>i</sub>
that refers to the object bound tor<sub>i</sub>
; the referenced type isr<sub>i</sub>
.
- 变量名(通常是左值)可以在
return
语句中移动,如果它命名为 隐式移动实体 :
An implicitly movable entity is a variable of automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type. In the following copy-initialization contexts, a move operation is first considered before attempting a copy operation:
- If the expression in a
return
([stmt.return]) orco_return
([stmt.return.coroutine]) statement is a (possibly parenthesized) id-expression that names an implicitly movable entity declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, or- [...]
- 从隐式移动实体的定义可以看出,只能隐式移动对象和(右值)引用。但是结构化绑定两者都不是。
An entity is a value, object, reference, [or] structured binding[...].
所以我认为不能隐式移动结构化绑定。
如果 y
是对象或引用,那么它将在 return y;
中隐式移动。
编辑:C++17 规定元组成员的结构化绑定是引用。 CWG 2313.
对此进行了更正