# Algorithms with n-ary callables

From: Pilar Latiesa <pilarlatiesa_at_[hidden]>
Date: Tue, 17 Nov 2020 11:45:30 +0100
Just a question to the C++ experts.

There are some std algorithms that tend to be much more verbose and
unclear than the plain loop counterpart. For example, compare:

for (std::size_t i = 0; i < v.size(); ++i)
u[i] = v[i] / std::sqrt(w[i]);

with:

std::transform(v.begin(), v.end(), w.begin(), u.begin(), [](auto a,
auto b) { return a / std::sqrt(b); });

The introduction of ranges library was a significant improvement:

std::ranges::transform(v, w, u.begin(), std::divides{}, {}, [](auto b)
{ return std::sqrt(b); });

Furthermore, thanks to the current and forthcoming range adaptors,
we'll be able to use algorithms in pieces of code that weren't
previously easily expressible with them. For example:

for (std::size_t i = 0; i < v.size(); ++i)
u[i] = v[i] * y[i] / std::sqrt(w[i]);

might be written:

std::ranges::transform(std::views::zip(v, w, y), u.begin(), [](auto
&&Proxy) { auto [a, b, c] = Proxy; return a * b / std::sqrt(c); });

to the algorithms such that they accept n-ary callables for iterators
with tuple-like iter_reference_t, where n is
tuple_size<iter_reference_t>?

I mean:

std::ranges::transform(std::views::zip(v, w, y), u.begin(), [](auto a,
auto b, auto c) { return a * b / std::sqrt(c); });

or also:

map<string, int> m;

auto sum = std::ranges::accumulate(m, 0, {}, [](auto &, auto i) { return i; });

though in this case we'd also have:

auto sum = std::ranges::accumulate(m | std::views::values, 0);