What are use cases for structured bindings?

Barring evidence to the contrary, I think Structured Bindings are merely a vehicle to deal with legacy API. IMHO, the APIs which require SB should have been fixed instead.

So, instead of

auto p = map.equal_range(k);
for (auto it = p.first; it != p.second; ++it)
    doSomethingWith(it->first, it->second);

we should be able to write

for (auto &e : map.equal_range(k))
    doSomethingWith(e.key, e.value);

Instead of

auto r = map.insert({k, v});
if (!r.second)
    *r.first = v;

we should be able to write

auto r = map.insert({k, v});
if (!r)
    r = v;

etc.

Sure, someone will find a clever use at some point, but to me, after a year of knowing about them, they are still an unsolved mystery. Esp. since the paper is co-authored by Bjarne, who's not usually known for introducing features that have such a narrow applicability.


Can you provide some other, possibly less obvious use cases for structured bindings? How else can they improve readability or even performance of C++ code?

More in general, you can use it to (let me say) unpack a structure and fill a set of variables out of it:

struct S { int x = 0; int y = 1; };

int main() {
    S s{};
    auto [ x, y ] = s;
    (void)x, void(y);
}

The other way around would have been:

struct S { int x = 0; int y = 1; };

int main() {
    S s{};
    auto x = s.x;
    auto y = s.y;
    (void)x, void(y);
}

The same is possible with arrays:

int main() {
    const int a[2] = { 0, 1 };
    auto [ x, y ] = a;
    (void)x, void(y);
}

Anyway, for it works also when you return the structure or the array from a function, probably you can argue that these examples belong to the same set of cases you already mentioned.


Another good example mentioned in the comments to the answer by @TobiasRibizel is the possibility to iterate through containers and unpack easily the contents.
As an example based on std::map:

#include <map>
#include <iostream>

int main() {
    std::map<int, int> m = {{ 0, 1 }, { 2, 3 }};
    for(auto &[key, value]: m) {
        std::cout << key << ": " << value << std::endl;
    }
}

Can you provide some other, possibly less obvious use cases for structured bindings?

They can be used to implement get<N> for structs - see magic_get's automatically generated core17_generated.hpp. This is useful because it provides a primitive form of static reflection (e.g. iterate over all members of a struct).