Home > Software design >  If we have ranges::zip and views::transform, why do we need ranges::zip_transform?
If we have ranges::zip and views::transform, why do we need ranges::zip_transform?

Time:11-24

In C 23, the ranges (sub)library has gained std::ranges::zip, which zips multiple ranges into a single range of std::tuple's (or pairs). This is nice, and precludes requiring implementing this ourselves, using boost::zip_iterator or resorting to this kind of a hack*.

However, we also get std::ranges::zip_transform. Why do we need it? After all , we can apply a ranges::views::transform to a zipped range, can't we? So, isn't zip_transform redundant?


* - that hack works well in C 11, and doesn't require tens of thousands of lines of code with concepts...

CodePudding user response:

If, in C , the concepts of "the ordered parameters of a function" and "a tuple" were identical or easily interchangeable, then you would be right.

... unfortunately, that is not the case. The difference is that std::ranges::zip_transform cuts out std::tuple's as the middle-man: Instead of constructing a tuple and passing it to the transform function, references to the range elements themselves are passed to the function!

So, instead of writing something like:

auto add = [](std::tuple t) { 
    return std::get<0>(t)   std::get<1>(t)   std::get<2>(t); 
};
auto elementwise_sum = 
    std::views::zip(v1, v2, v3) | std::views::transform(add);

we can write, instead:

auto add = [](auto a, auto b, auto c) { return a   b   c; };
auto elementwise_sum = std::views::zip_transform(add, v1, v2, v3);

nicer, right?

CodePudding user response:

In addition to what @einpoklum has explained about zip_transform, it is also worth noting that zip_transform will always forward each elements in a zipped result to the function. Which means it cannot be used as a drop-in replacement for zip | transform:

std::vector<int> v1, v2;
auto func = [](std::tuple<int, int> t){ return double{}; };

views::zip(v1, v2) | views::transform(func); // ok

// views::zip_transform(func, v1, v2); // this will not work

The second one will not work because it must receive a function that takes 2 parameters.


Sidenote, there are also views::adjacent/views::adjacent_transform, and their pairwise specializations that behaves similar to zip/zip_transform.

  • Related