24

Structured bindings have been introduced with c++17. They give the ability to declare multiple variables initialised from a tuple or struct.

This code compiles using a c++17 compiler.

#include <iostream>
#include <tuple>

int main() {
    auto tuple = std::make_tuple(1.0, 1);

    auto [ d, i ] = tuple;

    std::cout << "d=" << d << " i=" << i <<  '\n';

    return 0;
}

If I don't declare the variables with auto I get the error

error: expected body of lambda expression [d2 , i2] = tuple;

#include <iostream>
#include <tuple>

int main() {
    auto tuple = std::make_tuple(1.0, 2);

    double d2;
    int i2;

    [d2 , i2] = tuple;

    return 0;
}

I used clang version 4.0.0 and the compile option -std=c++1z.

Can I assign existing variables to a structured binding? Do I need to use auto?

schorsch312
  • 5,553
  • 5
  • 28
  • 57
  • 8
    Structured binding is only possible when defining and initializing variables. It's not possible as a general assignment (for that use [`std::tie`](http://en.cppreference.com/w/cpp/utility/tuple/tie)). – Some programmer dude Oct 16 '17 at 07:04

2 Answers2

19

The error message your got is pretty indicative of why it's only allowed with auto: lack of ambiguity that will make the grammar even more context dependent.

A pair of square brackets at the start of an expression indicates a lambda. What you are asking is for the standard to specify that sometimes [d2 , i2] is the beginning of a lambda that captures d2 and i2 by value, and at other times it's an unpacking assignment. All based on what follows it.

It's just not worth the complexity to add it to the language. Especially, since as Some programmer dude noted, you already have std::tie to do what you want with tuples.

Not only that, std::tie allows you to ignore some of the unpacked values, something structured bindings don't support yet. So it all boils down to having a more limited form of syntactic sugar, to do something the standard library already does with tuples.


Oh, and if you are disgruntles that std::tie works only with tuples, you can expand it to work with any POD yourself. Just look at this magic_get implementation. One can apply the same idea to constexpr transform a POD into a tuple of reference that can be fed to std::tie. Something like this:

std::tie(d2, i2) = magic_unpack(/*some POD that isn't a tuple*/);
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 3
    I don't think that's at all true. You could just add a keyword before a structured binding if auto is not being used, like so: `structured_binding [d2, i2] = tuple`. Someone else can come up with a syntax that looks nice, but it's the same effort to parse as with `auto`. You could then do this: `strucutured_binding [ bool d2, int i2]`. That's mainly why I would like the feature, because you could use structured bindings with explicit typing and with things that are not default constructible. – iPherian Feb 26 '20 at 13:37
  • @iPherian - Then you missed the point of the question. It's not why auto is the keyword, but why a keyword is required at all. – StoryTeller - Unslander Monica Feb 26 '20 at 13:38
  • @StoryTeller-UnslanderMonica Agree on that – Still iPherian met a good point – would be nice e.g. to automatically change signedness or size of integrals. `auto [int n, double d, /* and the defaulting */ x]` would be totally fine for in my eyes, though, no need for *yet another* keyword... Maybe nice, too, being able to combine both values and references: `auto [&r, v]`? – Aconcagua Jun 23 '22 at 08:47
  • That's not the reason to not using `std::tuple [d1, i2] = tuple`. – Tuff Contender Jul 21 '22 at 17:50
  • @TuffContender - No, the reason to not do *that* is that C++ is not pure token soup, but really does divide between keywords and library types. What you just proposed makes no sense in how the language works. – StoryTeller - Unslander Monica Jul 21 '22 at 19:51
  • I found "If I use structured bindings, the types of the bindings are what matters in a strong/concrete API boundary, the whole-object type is irrelevant" in http://wg21.link/p0480r1 , though I'm still a little suspicious of it. – Tuff Contender Jul 22 '22 at 02:40
4

Also, you can using std::tie() to unpack the tuple into its individual components. Such as

#include <iostream>
#include <tuple>

int main() {
    auto tuple = std::make_tuple(1.0, 1);
    double d2;
    int i2;
    std::tie(d2, i2) = tuple;

    std::cout << "d2=" << d2 << " i2=" << i2 <<  '\n';

    return 0;
}
msc
  • 33,420
  • 29
  • 119
  • 214