Yesterday I've seen an interesting question here on SO about structured binding.
We can sum up it as it follows. Consider the example code below:
#include <tuple>
#include <type_traits>
int main() {
auto tup = std::make_tuple(1, 2);
auto & [ a, b ] = tup;
// the following line won't compile for a isn't a reference
// static_assert(std::is_reference_v<decltype(a)>);
}
In this case decltype(a)
is int
(probably) because of this bullet (working draft):
if
e
is an unparenthesized id-expression naming a structured binding [...],decltype(e)
is the referenced type as given in the specification of the structured binding declaration
Here is a snippet on wandbox provided by @Curious in the comments for those that are interested. It shows that actually a
isn't a reference, nothing more.
So far so good for the original question, OP asked why it was int
instead of int &
and the standard says that looked like an acceptable answer.
Anyway, I'd like to know why the committee decided so. At the end of the day, a
refers to an element in the tuple and I can modify that element through a
. In other terms, the declaration of a
looks like the one of a reference, it behaves similarly to a reference but it's not a reference.
I can live with this, but I'd like to know what are the reasons behind that. Why decltype(a)
cannot be simply int &
? Is there a meaningful reason that a profane can understand?
decltype(x)
, wherex
is a structured binding, names the referenced type of that structured binding. In the tuple-like case, this is the type returned bystd::tuple_element
, which may not be a reference even though the structured binding itself is in fact always a reference in this case. This effectively emulates the behavior of binding to a struct whose non-static data members have the types returned bytuple_element
, with the referenceness of the binding itself being a mere implementation detail.
This topic has been covered before (look in the structured-bindings tag) and the behavior you're talking about is even addressed in the second answer. However, the rationale is spelled out in p0144r2 section 3.5:
Should the syntax be extended to allow
const/&
-qualifying individual names' types?For example:
auto [&x, const y, const& z] = f(); // NOT proposed
We think the answer should be no. This is a simple feature to store a value and bind names to its components, not to declare multiple variables. Allowing such qualification would be feature creep, extending the feature to be something different, namely a way to declare multiple variables.
If we do want to declare multiple variables, we already have a way to spell it:
auto val = f(); T& x = get<0>(val); T2 const y = get<1>(val); T3 const& z = get<2>(val);
来源:https://stackoverflow.com/questions/44695684/structured-bindings-when-something-looks-like-a-reference-and-behaves-similarly