12

Consider the following code that uses structured bindings from C++17:

int a = 0, b = 0;
auto [x, y] = std::tie(a, b);
y = 1;
std::cout << a << ' ' << b << '\n';

Since I used auto, I would expect the code to print 0 0 as y should be a copy. However, it prints 0 1. Why? I thought that a bare auto never deduces a reference.

s3rvac
  • 9,301
  • 9
  • 46
  • 74

1 Answers1

19

As cppreference notes, the portion of the declaration preceding [ (i.e. auto in your case) does not apply to the introduced identifiers. Instead, it applies to a hidden variable that is created by the compiler under the covers. Your structured-binding declaration

auto [x, y] = std::tie(a, b);

is roughly equivalent to

auto e = std::tie(a, b);
decltype(std::get<0>(e)) x = std::get<0>(e);
decltype(std::get<1>(e)) y = std::get<1>(e);

As you can see, auto is applied to the hidden variable e and not to the declaration of x and y. The type of e is std::tuple<int&, int&>, and decltype(std::get<1>(e)) gives you int&.

s3rvac
  • 9,301
  • 9
  • 46
  • 74
  • 4
    Usage of `decltype` here is slightly incorrect. `std::get` for tuples always returns a reference (to allow mutating tuple elements), but `auto [x] = std::tuple(5)` will deduce `int`, not `int&`. correct type here is `tuple_element_t<0, decltype(e)>` – Revolver_Ocelot Dec 08 '17 at 16:40
  • 3
    @Revolver_Ocelot `x` is an alias to the member of the hidden variable. It ___is___ a reference in this sense. Though `decltype` has special handling that makes it not appear like a reference. – cpplearner Dec 08 '17 at 16:51
  • 1
    @Revolver `tuple_element<...>&` – Barry Dec 08 '17 at 19:20