Consider an example:
#include <iostream> #include <type_traits> #include <tuple> int main() { auto tup = std::make_tuple(1, 2); auto [ a, b ] = tup; decltype(auto) e = a; std::cout << std::boolalpha << std::is_reference_v<decltype(e)> << std::endl; }
clang (output: false
) and gcc (output: true
) are disagreeing in this simple case. Having in mind e.g. this Q&As should the e
be a reference or is it a gcc bug? Or maybe the code is ill-formed?
The identifers themselves are references. From [dcl.struct.bind]/3:
Given the type Ti designated by
std::tuple_element<i, E>::type
, each vi is a variable of type “reference to Ti” initialized with the initializer, where the reference is an lvalue reference if the initializer is an lvalue and an rvalue reference otherwise; the referenced type is Ti.
That is, a
and b
are both int&&
.
But the way decltype(auto)
actually behaves comes from [dcl.type.auto.deduct]:
If the placeholder is the
decltype(auto)
type-specifier,T
shall be the placeholder alone. The type deduced forT
is determined as described in [dcl.type.simple], as thoughe
had been the operand of thedecltype
.
This wording is really awkward, but ultimately:
decltype(auto) e = a; ~~~~~~~~~~~~~~
means:
decltype( a ) e = a; ~~~~
and decltype(a)
means, from [dcl.type.simple]/4.1:
if
e
is an unparenthesized id-expression naming a structured binding ([dcl.struct.bind]),decltype(e)
is the referenced type as given in the specification of the structured binding declaration;
The referenced type of a
is int
, so e
must be an int
. Which means it's not a reference, and clang is correct. Filed 81176.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With