结构化绑定是否应作为 C++20 中的右值从函数返回?

Fed*_*dor 23 c++ language-lawyer lvalue-to-rvalue c++20

考虑一个 C++20 程序,其中函数中foo有一个结构化绑定auto [y]。函数返回y,它被转换为对象类型AA可以从右值引用的常量引用构造。

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

根据C++20语言标准应该选择哪一个构造函数?

Clang 选择A(const int &)和 GCC 选择A(int &&),演示:https : //gcc.godbolt.org/z/5q779vE6T

是否有一个编译器不支持这方面的标准?

cpp*_*ner 5

我相信 Clang 是正确的。

TL;DR:一些左值可以隐式移动,但结构化绑定不是这样的左值。

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

[dcl.struct.bind]/1 :

结构化绑定声明引入标识符列表的标识符, , ,...作为结构化绑定的名称。v0v1v2

[dcl.struct.bind]/4 :

每个都是类型左值的名称,该左值引用绑定到的对象;引用的类型是.viTiriri

  1. 如果变量名(通常是左值)return命名为隐式可移动实体,则它可以在语句中移动

隐式可动实体是自动存储持续时间的变量,它是任一的非易失性对象或一个rvalue参照非易失性对象类型。在以下复制初始化上下文中,在尝试复制操作之前首先考虑移动操作:

  • 如果表达return([stmt.return])或co_­return([stmt.return.coroutine])语句是一个(可能是括号)ID-表达名称隐式可动实体主体或声明参数声明子句的最里面的封闭函数或lambda 表达式,或
  • [...]
  1. 从隐式可移动实体的定义中可以看出,只有对象和(右值)引用可以隐式移动。但结构化绑定两者都不是。

[基本.pre]/3 :

实体是值、对象、引用或[或]结构化绑定[...]。

所以我相信结构化绑定不能被隐式移动。

如果y是一个对象或引用,那么它将在return y;.


编辑:编写的 C++17 指定元组成员的结构化绑定是引用。这已由CWG 2313纠正。