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?
I believe that Clang is correct.
TL;DR: some lvalues can be implicitly moved, but a structured binding is not such a lvalue.
A structured binding declaration introduces the identifiers
v0
,v1
,v2
,… of the identifier-list as names of structured bindings.
Each
vi
is the name of an lvalue of typeTi
that refers to the object bound tori
; the referenced type isri
.
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]) 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[...].
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.