为什么 `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::tuple
和 hana::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
标签 S
,hana::make<S>(...)
必须创建包含 ...
的标签 S
的 Sequence
。但是,range
必须在某个区间内包含连续的 integral_constant
。因此,如果 range
是 Sequence
,hana::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_constant
s 8,3,5,10
的range
,没有意义。 range
不能是 Sequence
的另一个类似例子是 permutations
算法。 permutations
算法采用 Sequence
和 returns 一个 Sequence
的 Sequence
包含所有排列。显然,由于 range
只能容纳 integral_constant
,因此尝试创建 range
的 range
是没有意义的。这样的例子比比皆是。
换句话说,range
过于专业化,无法对 Sequence
概念进行建模。拥有这种专用结构的好处是它的编译时效率很高。缺点是它不是通用容器,无法对其进行某些操作(如 zip
)。但是,如果您知道权衡是什么,您完全可以采用 range
并将其转换为完整的序列。
#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::tuple
和 hana::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
标签 S
,hana::make<S>(...)
必须创建包含 ...
的标签 S
的 Sequence
。但是,range
必须在某个区间内包含连续的 integral_constant
。因此,如果 range
是 Sequence
,hana::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_constant
s 8,3,5,10
的range
,没有意义。 range
不能是 Sequence
的另一个类似例子是 permutations
算法。 permutations
算法采用 Sequence
和 returns 一个 Sequence
的 Sequence
包含所有排列。显然,由于 range
只能容纳 integral_constant
,因此尝试创建 range
的 range
是没有意义的。这样的例子比比皆是。
换句话说,range
过于专业化,无法对 Sequence
概念进行建模。拥有这种专用结构的好处是它的编译时效率很高。缺点是它不是通用容器,无法对其进行某些操作(如 zip
)。但是,如果您知道权衡是什么,您完全可以采用 range
并将其转换为完整的序列。