为什么 `boost::hana::range_c` 不是序列?

Why is `boost::hana::range_c` not a Sequence?

#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");
}

我想在 hana::tuplehana::range_c 上使用 hana::zip,但 hana::range_c 不被视为 序列 ,这是 hana::zip 的要求。这个决定背后的原因是什么?我如何(惯用地)在尊重该决定的同时实现我的目标?

首先有几种解决方法:

解决方案 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) {
    // ...
}));

解决方案 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];
    // ...
});

解决方案 3

auto types = hana::make_tuple(std::forward<T>(args)...);
hana::size_c<sizeof...(T)>.times.with_index([&](auto i) {
    auto& x = types[i];
    // ...
});

解决方案(1)的缺点是要对每个args进行复制,因为zip returns是一个序列序列,并且Hana 中的一切都是按价值计算的。由于这可能不是您想要的,您应该在解决方案 (2)(3) 之间选择您喜欢的任何一个,它们实际上是等价的。

现在,range 不模拟 Sequence 概念的原因是因为那没有意义。 Sequence 概念要求我们能够使用 hana::make 函数创建任意 Sequence。因此,对于任何 Sequence 标签 Shana::make<S>(...) 必须创建包含 ... 的标签 SSequence。但是,range 必须在某个区间内包含连续的 integral_constant。因此,如果 rangeSequencehana::make<hana::range_tag>(...) 应该包含 ... 是什么,如果 ... 不是,这将打破 range 的不变量连续 integral_constant 秒。考虑例如

hana::make<hana::range_tag>(hana::int_c<8>, hana::int_c<3>,
                            hana::int_c<5>, hana::int_c<10>)

这应该是一个包含integral_constants 8,3,5,10range,没有意义。 range 不能是 Sequence 的另一个类似例子是 permutations 算法。 permutations 算法采用 Sequence 和 returns 一个 SequenceSequence 包含所有排列。显然,由于 range 只能容纳 integral_constant,因此尝试创建 rangerange 是没有意义的。这样的例子比比皆是。

换句话说,range 过于专业化,无法对 Sequence 概念进行建模。拥有这种专用结构的好处是它的编译时效率很高。缺点是它不是通用容器,无法对其进行某些操作(如 zip)。但是,如果您知道权衡是什么,您完全可以采用 range 并将其转换为完整的序列。