#include <string>
#include <utility>
#include <vector>
#include <boost/hana.hpp>
namespace hana = boost::hana;
template <typename ...T>
void indexed_T_work(T&& ...args)
{
auto indices = hana::range_c<std::size_t, 0, sizeof...(T)>;
auto types = hana::make_tuple(std::forward<T>(args)...);
hana::for_each(
hana::zip(indices, types)
, [](auto&& pair_) { /* Do index-dependent work with each `T` */ }
);
}
int main()
{
indexed_T_work(5, 13, std::vector<std::string>{}, 32.f, 42, "foo");
}
I'd like to use hana::zip
on a hana::tuple
and hana::range_c
, but hana::range_c
is not considered a Sequence, which is a requirement for hana::zip
. What is the reasoning behind this decision? How can I (idiomatically) accomplish my goal while respecting that decision?
First, there are several solutions:
Solution 1
auto indices = hana::to<hana::tuple_tag>(hana::range_c<std::size_t, 0, sizeof...(T)>);
auto types = hana::make_tuple(std::forward<T>(args)...);
hana::for_each(hana::zip(indices, types), hana::fuse([](auto i, auto&& x) {
// ...
}));
Solution 2
auto indices = hana::range_c<std::size_t, 0, sizeof...(T)>;
auto types = hana::make_tuple(std::forward<T>(args)...);
hana::for_each(indices, [&](auto i) {
auto& x = types[i];
// ...
});
Solution 3
auto types = hana::make_tuple(std::forward<T>(args)...);
hana::size_c<sizeof...(T)>.times.with_index([&](auto i) {
auto& x = types[i];
// ...
});
Solution (1) has the disadvantage of making a copy of each args
because zip
returns a sequence of sequences, and everything in Hana is by value. Since this is probably not what you want, you should pick whichever you prefer between solutions (2) and (3), which are really equivalent.
Now, the reason why range
s do not model the Sequence
concept is because that wouldn't make sense. The Sequence
concept requires that we be able to create an arbitrary Sequence
using the hana::make
function. Hence, for any Sequence
tag S
, hana::make<S>(...)
must create a Sequence
of tag S
that contains ...
. However, a range
must contain contiguous integral_constant
s in some interval. Hence, if range
was a Sequence
, hana::make<hana::range_tag>(...)
should contain whatever ...
is, which breaks the invariant of a range
if ...
are not contiguous integral_constant
s. Consider for example
hana::make<hana::range_tag>(hana::int_c<8>, hana::int_c<3>,
hana::int_c<5>, hana::int_c<10>)
This should be a range
containing integral_constant
s 8,3,5,10
, which does not make sense. Another similar example showing why a range
can't be a Sequence
is the permutations
algorithm. The permutations
algorithm takes a Sequence
and returns a Sequence
of Sequence
s containing all the permutations. Clearly, since a range
can only hold integral_constant
s, it does not make sense to try and create a range
of range
s. Examples like this abound.
In other words, range
s are too specialized to model the Sequence
concept. The upside of having such a specialized structure is that it's very compile-time efficient. The downside is that it's not a general-purpose container and some operations can't be done on it (like zip
). However, you can totally take a range
and convert it to a full-blown sequence, if you know what the tradeoff is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With