C++20中,是否应该将结构化绑定作为rvalue从函数返回?

26

考虑一个C++20程序,在函数foo中有一个结构绑定auto [y]。该函数返回y,它被转换为A类型的对象。可以使用const引用或rvalue引用构造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

其中一个编译器在这方面尚未支持这一标准吗?


3
似乎与结构化绑定无关,是吗? - Igor R.
与所选A的构造函数有关,而不是绑定。一般来说,这些类型转换构造函数应该是显式的。这些隐式类型转换构造函数可能会很麻烦。 - Pepijn Kramer
2
Clang是正确的,因为表示结构化绑定的id表达式是一个左值。 - Language Lawyer
如果我们改为写成 int y = 1; return y;,那么clang会使用 int&& 构造函数。如果 id-expression 表示的是一个变量而不是左值(或者两个编译器在这种情况下都是错误的,或者有一些规则适用于这种情况但不适用于结构化绑定,或者其他原因),那么是不是两个编译器都是错误的呢? - eerorika
1
@eerorika 在你的例子中,y 是一个 int,因此在返回时符合 rvalue 转换的条件。在 op 的例子中,y 实际上是一个结构化绑定声明的某个未命名对象的子对象的引用。如果它是左值引用,则会停止移动。但我仍然无法确定哪一个是正确的 :( - NathanOliver
显示剩余8条评论
1个回答

6
我相信Clang是正确的。 TL;DR:某些lvalue可以被隐式移动,但结构化绑定不是这样的lvalue。 1.结构化绑定的名称是lvalue:

[dcl.struct.bind]/1:

一个结构化绑定声明将标识符列表中的标识符v0v1v2等引入为结构化绑定的名称。

[dcl.struct.bind]/4:

每个 vi 都是类型为 Ti 的左值的名称,该左值引用绑定到 ri 的对象;所引用的类型是 ri

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

隐式可移动实体是具有自动存储期的变量,它是非易失性对象或非易失性对象类型的右值引用。 在以下复制初始化上下文中,在尝试复制操作之前首先考虑移动操作:

  • 如果return ([stmt.return])或co_­return ([stmt.return.coroutine])语句中的表达式是一个(可能带括号的)标识表达式,该表达式命名了在最内层封闭函数或lambda-expression参数声明子句中声明的隐式可移动实体,或
  • [...]
正如隐式可移动实体的定义所示,只有对象和(右值)引用可以被隐式移动。但是结构化绑定并不属于这两种情况。

[basic.pre]/3:

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

因此,我认为结构化绑定不能被隐式移动。

如果y是一个对象或引用,则在return y;中它将被隐式移动。


编辑:根据C++17的规定,结构化绑定到元组成员是引用。这一点已经由CWG 2313进行了修正。

关于可以看到在隐式可移动实体的定义中,只有对象和(rvalue)引用可以被隐式移动。但是结构化绑定不是。我不确定这是否正确。Rvalue引用也是lvalue,并且根据此,如果我理解正确,绑定可以是rvalue引用。 - NathanOliver
同时,我认为声明 y 不是一个对象是不正确的。 - user1095108
绑定仅将y设置为int。返回语句返回一个通过转换构造函数创建的A对象。绑定不应干扰返回工作方式。 - Cleiton Santoia Silva
@user1095108 我也感觉不对,但这是 [tag:language-lawyer]。 - cpplearner
尽管使用"return {y}"时,两者都变成了const int&。https://gcc.godbolt.org/z/3nxYno8nn - Cleiton Santoia Silva
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接