# Re: Algorithms with n-ary callables

From: Barry Revzin <barry.revzin_at_[hidden]>
Date: Tue, 17 Nov 2020 08:59:43 -0600
On Tue, Nov 17, 2020 at 4:46 AM Pilar Latiesa via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> 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); });
>
> The question is: would it be theoretically possible to add overloads
> 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); });
>

This sort of thing is sufficiently common that
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2214r0.html
suggests a named view:

ranges::copy(
zip_transform([](auto a, auto b, auto c){ return a * b / std::sqrt(c);
}, z, w, y),
u.begin());

>
> or also:
>
> map<string, int> m;
>
> auto sum = std::ranges::accumulate(m, 0, {}, [](auto &, auto i) { return
> i; });
>

But generally, you're not looking for a different algorithm. You're looking
for a function adapter. Boost.Hof calls this unpack (
https://www.boost.org/doc/libs/master/libs/hof/doc/html/include/boost/hof/unpack.html
):

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

Which you could also use in the previous example:

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

Barry

>
> though in this case we'd also have:
>
> auto sum = std::ranges::accumulate(m | std::views::values, 0);
>

> Are there cases in which adding such overloads would cause ambiguities?
>
> Pili
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]

>