I have a POD struct
struct query{
int l, r, ans;
};
and I want to write a range-based loop:
std::vector<query> q;
for (auto [l, r, &ans]: q) {
// perhaps I want to modify l and r here, but I want to store the result in ans.
// Furthermore, I will reuse Q with the same **original** l and r later, but
// don't want to create temporary variables to achieve the same effect
}
There are many obvious quick solutions to this "problem", involving just making an external array for ans, making the temporaries, or maybe hacking something together with std::tie:
int ty, l, r, x;
int& ans = elem.ans;
std::tie(ty, l, r, x, std::ignore) = std::tie(elem.ty, elem.l, elem.r, elem.x, elem.ans);
so yes, I'm grieving over 2 lines of extra code. But any nicety of c++17 and c++20 features I can abuse to write clearer and shorter code, I want to know.
For the record, code snippet 1 doesn't compile; as per cppreference, it has to be an identifier, without any ref-qualifiers. So I don't think structured bindings will work here. But maybe some std::tie magic or some other language feature I'm not aware of will solve my issue? Any ideas appreciated.
Well, you can always create structured bindings to another tuple...
query q {1, 2, 0};
auto [l, r, ans] = std::make_tuple(q.l, q.r, std::ref(q.ans));
ans = l + r;
std::cout << q.ans; // 3
std::make_tuple
will create a tuple holding values that are copied/moved from each corresponding argument, unless that argument is a std::reference_wrapper
. In that case, the tuple will refer to whatever the reference wrapper referred to. std::reference_wrapper
is used in a lot of places in the standard library to explicitly require reference semantics.
Now, if you are willing to pass your vector through a transform view that does the above to every member, you can kinda get what you want
auto make_binding = std::views::transform([](query& o) { return std::make_tuple(o.l, o.r, std::ref(o.ans)); });
for (auto [l, r, ans]: q | make_binding) {
}