[Boost.Range] combine, native range-for, and destructuring

I want to go through two vectors at the same time, and the way to do this is to "zip" the
items from each into a tuple. boost::combine is a function for that.
for (auto&[def,residue] : boost::combine(playdef, residues)) {
gives me an error
1>e:\scratch\c++code\scratchproject2\fizzbuzz\fizzbuzz.cpp(66): error C2440:
'initializing': cannot convert from
'boost::tuples::cons

On Sat, 14 Apr 2018 at 08:02 John M. Dlugosz via Boost-users < boost-users@lists.boost.org> wrote:
I want to go through two vectors at the same time, and the way to do this is to "zip" the items from each into a tuple. boost::combine is a function for that.
for (auto&[def,residue] : boost::combine(playdef, residues)) {
gives me an error
<snip>
Trying to explore the behavior in pieces, I try:
for (auto row : boost::combine(playdef, residues)) { auto&[def, residue] = row; // line 1 row.get<1>() = 17; // line 2 residue= 42; // line 3
Now line2 does work, and I note that assignment goes through and updates the original `residues` vector.
The destructuring on line 1 does compile now, being on a separate line. But line 3 gives me an error about not being able to assign to a crazy complicated type.
What's going on? Is Boost.Range zipped ranges simply not compatible with the native language features?
Hi John,
I'm not en expert on this library, but I have run into the first of your
problems before.
When dereferencing a normal iterator, the iterator returns a reference to
the actual object being pointed to. The zip iterator can not do this,
instead it returns a tuple of references to the the underlying objects as a
temporary.
Consider:
vector<int> i;
vector<float> j;
*boost::range::combine(i, j); // This must return something like
tuple

On 14 April 2018 at 04:34, John M. Dlugosz via Boost-users < boost-users@lists.boost.org> wrote:
I want to go through two vectors at the same time, and the way to do this is to "zip" the items from each into a tuple. boost::combine is a function for that.
I've run into this problem as well, it's a real shame it doesn't work, because if you would be able to use boost::combine with (C++17) structured bindings, one can completely abstract away (if it would work) the zip-iterator (you wouldn't see it even though that's what's happening under the hood)... degski PS: I did not report it because I wasn't sure the problem was not related to the MS-implementation of structured bindings (this is a while ago), and I did not want to attract anymore flak for being a ms-boy. It seems it isn't then.

On 14 April 2018 at 17:49, degski
On 14 April 2018 at 04:34, John M. Dlugosz via Boost-users < boost-users@lists.boost.org> wrote:
I want to go through two vectors at the same time, and the way to do this is to "zip" the items from each into a tuple. boost::combine is a function for that.
I've run into this problem as well, it's a real shame it doesn't work, because if you would be able to use boost::combine with (C++17) structured bindings, one can completely abstract away (if it would work) the zip-iterator (you wouldn't see it even though that's what's happening under the hood)...
The construct does work with std:tie, but that's at least 3 more lines of code and does not look as "sexy" as the (not working) structured bindings approach (sorry for the nerdy "does not look sexy" comment). degski

John M. Dlugosz via Boost-users wrote:
for (auto&[def,residue] : boost::combine(playdef, residues)) {
gives me an error
This fails, because the deref operator of zip_iterator generates a prvalue (of a tuple of references). Instead, you can use - for (auto [x, y] : combine(...)) {...} - for (auto const& [x, y] : combine(...)) {...} - for (auto&& [x, y] : combine(...)) {...}
for (auto row : boost::combine(playdef, residues)) { auto&[def, residue] = row; // line 1 row.get<1>() = 17; // line 2 residue= 42; // line 3
Now line2 does work, and I note that assignment goes through and updates the original `residues` vector.
The destructuring on line 1 does compile now, being on a separate line. But line 3 gives me an error about not being able to assign to a crazy complicated type.
Hmm..., with boost (develop branch) + GCC 7.3 or Clang trunk, the following code runs fine: std::vector<int> v1{1, 1, 1}; std::vector<int> v2{2, 2, 2}; for (auto&& tpl : boost::range::combine(v1, v2)) { auto [x, y] = tpl; // `auto&`, `auto const&` and `auto&&` also work fine x = 10; y = 20; } for (auto&& [x, y] : boost::range::combine(v1, v2)) { x = 200; y = 200; } Regards, Michel

On Tue, 17 Apr 2018 at 11:00 Michel Morin via Boost-users < boost-users@lists.boost.org> wrote:
Hmm..., with boost (develop branch) + GCC 7.3 or Clang trunk, the following code runs fine:
std::vector<int> v1{1, 1, 1}; std::vector<int> v2{2, 2, 2};
for (auto&& tpl : boost::range::combine(v1, v2)) { auto [x, y] = tpl; // `auto&`, `auto const&` and `auto&&` also work fine x = 10; y = 20; }
for (auto&& [x, y] : boost::range::combine(v1, v2)) { x = 200; y = 200; }
FWIW, I just checked, and this works in the develop, but not master or 1.67. -- chris
participants (4)
-
Chris Glover
-
degski
-
John M. Dlugosz
-
Michel Morin