Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shall structured binding be returned from a function as rvalue in C++20?

Tags:

Consider a C++20 program where in function foo there is a structured binding auto [y]. The function returns y, which is converted in object of type A. A can be constructed either from const reference of from rvalue-reference.

#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(); } 

Which one of the constructors shall be selected according to C++20 language standard?

Clang selects A(const int &) and GCC selects A(int &&), demo: https://gcc.godbolt.org/z/5q779vE6T

Does one of the compilers not support yet the standard in that respect?

like image 543
Fedor Avatar asked Aug 26 '21 15:08

Fedor


People also ask

What is structured binding in a structured binding declaration?

A structured binding declaration performs the binding in one of three possible ways, depending on E. Case 1 : if E is an array type, then the names are bound to the array elements. Case 2 : if E is a non-union class type and tuple_size is a complete type, then the “tuple-like” binding protocol is used.

Why does my binding fail when returning a tuple?

As usual, the binding will fail if e is a non-const lvalue reference: decltype(x), where x denotes a structured binding, names the referenced type of that structured binding. In the tuple-like case, this is the type returned by std::tuple_element, which may not be a reference even though a hidden reference is always introduced in this case.

What is a referenced type in a structured binding?

Each structured binding has a referenced type, defined in the description below. This type is the type returned by decltype when applied to an unparenthesized structured binding. Each identifier in the identifier-list becomes the name of an lvalue that refers to the corresponding element of the array.

What are structured bindings in C++17?

Structured binding is one of the newest features of C++17 that binds the specified names to subobjects or elements of initializer. In simple words, Structured Bindings give us the ability to declare multiple variables initialized from a tuple or struct.


1 Answers

I believe that Clang is correct.

TL;DR: some lvalues can be implicitly moved, but a structured binding is not such a lvalue.

  1. The name of a structured binding is an lvalue:

[dcl.struct.bind]/1:

A structured binding declaration introduces the identifiers v0, v1, v2,… of the identifier-list as names of structured bindings.

[dcl.struct.bind]/4:

Each vi is the name of an lvalue of type Ti that refers to the object bound to ri; the referenced type is ri.

  1. An variable name (which is normally an lvalue) can be moved in a return statement if it names an implicitly movable entity:

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. As can be seen in the definition of implicitly movable entity, only objects and (rvalue) references can be implicitly moved. But a structured binding is neither.

[basic.pre]/3:

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

So I believe that a structured binding cannot be implicitly moved.

If y were an object or reference, then it would be implicitly movable in return y;.


Edit: C++17 as written specified that structured bindings to tuple members are references. This was corrected by CWG 2313.

like image 113
cpplearner Avatar answered Oct 18 '22 15:10

cpplearner