I don't quite understand the base trick from Daisy Hollman's talk:
https://youtu.be/15etE6WcvBY?t=2670
Enumerating a pack using c++20 lamdas with explicit template arguments.
#include <iostream>
#include <utility>
template <typename Function, typename ...Ts>
void enumerate_pack(Function f, Ts... args) {
[&]<std::size_t... Idxs>(std::index_sequence<Idxs...>) { (f(Idxs, args), ...); }
(std::make_index_sequence<sizeof...(args)>{});
}
int main() {
enumerate_pack([](std::size_t i, auto arg) { std::cout << i << ": " << arg << "\n"; }, "hello",
42, "world", 73.2);
}
My problem with it is this part:
(f(Idxs, args), ...);
This looks to me like we are "passing a type to a function". OK, we are expanding the pack so it's a single type and not the whole pack, but it's still a "type", to my eyes. And even more confusingly, the second argument args
is the name of a local variable - again a pack, but a variable nonetheless. The usage of args
makes much more sense to me.
I would have thought the syntax should be:
[&]<std::size_t... Idxs>(std::index_sequence<Idxs...> idxs) { (f(idxs, args), ...); }
Note that I have now given a name to the parameter pack (idxs
) and used that. This doesn't compile.
Is the syntax here just a little baroque, or is there something deeper I am missing?
This
f(Idxs, args), ...
Because both Idxs
and args
are parameter packs, expands to:
f(0, args0), f(1,args1), .....
If you replace Idxs
with a std::index_sequence<Idxs...>
then it isnt a pack, it does not expand and f(std::index_sequence<Idxs...>, argX)
is the wrong signature for f
. There is no overload for f
that takes a std::index_sequence<Idxs...>
as first paramter.
The only purpose of the index sequence is to get your hands on the indices. The index sequence itself is not used, hence needs not be named.