在 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:一些左值可以隐式移动,但结构化绑定不是这样的左值。

  1. 结构化绑定的名称是左值:

[dcl.struct.bind]/1:

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.

[dcl.struct.bind]/4:

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>.

  1. 变量名(通常是左值)可以在 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
  • [...]
  1. 从隐式移动实体的定义可以看出,只能隐式移动对象和(右值)引用。但是结构化绑定两者都不是。

[basic.pre]/3:

An entity is a value, object, reference, [or] structured binding[...].

所以我认为不能隐式移动结构化绑定。

如果 y 是对象或引用,那么它将在 return y; 中隐式移动。


编辑:C++17 规定元组成员的结构化绑定是引用。 CWG 2313.

对此进行了更正