In ADSP Podcast Episode 91 (2022-08-19, around 14:30 ... 16:30) Bryce Lelbach and Conor Hoekstra talk about an example application of the (hopefully) upcoming C++23 ranges views zip_transform
and repeat
: scaling a range of values by the (non-zero) minimum value of that range.
Since to my knowledge at the time of writing, no library of any compiler implements these yet (and no link was given), I wonder how to implement it. The closest I came up with, was
auto scale_by_min(auto&& range)
{
auto m = std::ranges::min(range);
return std::views::zip_transform(
range,
std::views::repeat(m),
[](auto x, auto min)
{
return x / min;
}
);
}
((non-working) example in godbolt). Did I get it right?
Edit / Clarification:
Replacing the return statement by
return range | std::views::transform([m](auto x){ return x / m; });
it works in C++20, also without zip_transform
and repeat
, as correctly stated in a comment. This question is not about conciseness, style, or meaningfulness of the example. I just try to get the syntax right for using the upcoming ranges-views.
Did I get it right?
No. zip_transform
accepts variadic template arguments as input ranges, the first argument of zip_transform
must be the transform functor, so you should
auto m = std::ranges::min(range);
return std::views::zip_transform(
std::divides{},
range,
std::views::repeat(m)
);
It's worth noting that views::repeat(m)
gives you an infinite range, which makes zip_transform_view
not model sized_range
. You can pass the second parameter of repeat_view
by detecting whether the range
is sized_range
, e.g.
auto m = std::ranges::min(range);
auto repeat = [&] {
if constexpr (std::ranges::sized_range<decltype(range)>)
return std::views::repeat(m, std::ranges::size(range));
else
return std::views::repeat(m);
}();
return std::views::zip_transform(std::divides{}, range, repeat);
which makes zip_transform_view
preserve the properties of sized_range
.