如何对数字元组应用动作元组?
How to apply a tuple of actions on tuple of numbers?
我有两个元组,一个包含值,另一个包含对这些值的操作。
现在我想对每个值应用相应的操作,代码越少越好 "overhead"。
类似于下面的简化示例。
#include <iostream>
#include <boost/hana.hpp>
namespace hana = boost::hana;
using namespace hana::literals;
struct ThinkPositive
{
void operator()(int &val) const
{
std::cout << "Think positive!\n";
val = std::abs(val);
}
};
struct Nice
{
void operator()(int &val) const
{
std::cout << val << " is nice!\n";
}
};
void numbers()
{
auto handlers = hana::make_tuple(Nice{}, ThinkPositive{});
auto nums = hana::make_tuple(5, -12);
auto handlers_and_nums = hana::zip(handlers, nums);
hana::for_each(handlers_and_nums, [](auto &handler_num) {
handler_num[0_c](handler_num[1_c]);
});
auto result = hana::transform(handlers_and_nums, [](const auto &handler_num) {
return handler_num[1_c];
});
hana::for_each(result, [](const auto num) {
std::cout << "got " << num << '\n';
});
}
int main()
{
numbers();
}
虽然上面的示例有效,但就地修改 nums 的内容会更好。
有没有办法就地修改 nums?
你可以使用 zip_with
,但它似乎违背了它的本质(它要求函数实际上 return 一些东西,但是你的运算符 ()
return 什么都没有:
auto special_compose = [](auto&& l, auto&& r){ l(r); return 0; };
hana::zip_with(special_compose, handlers, nums);
如果你可以让你的运营商 return 一些东西,你可以选择 lockstep
:
hana::fuse(hana::fuse(hana::lockstep(hana::always(0)))(handlers))(nums);
应该有类似 lockstep
的定义,但没有外部 f
调用,但我在文档中找不到任何内容。
更标准的解决方案(不符合您对尽可能少的代码开销的要求):
template<typename Fs, typename Params, size_t... is>
void apply_in_lockstep_impl(Fs&& fs, Params&& ps, std::index_sequence<is...>){
int x[] = { (fs[hana::integral_c<size_t,is>](ps[hana::integral_c<size_t,is>]),0)... };
}
template<typename Fs, typename Params>
void apply_in_lockstep(Fs&& fs, Params&& ps){
static_assert(hana::size(fs) == hana::size(ps), "");
apply_in_lockstep_impl(std::forward<Fs>(fs),
std::forward<Params>(ps),
std::make_index_sequence<decltype(hana::size(ps))::value>{});
}
但在调用站点它更漂亮:
apply_in_lockstep(handlers, nums);
正如评论中指出的那样,另一个间接级别也有帮助。
在这里,这意味着将序列转换为指针序列,通过指针修改原始值。
auto nums_ptr = hana::transform(nums, [](auto &num) { return # });
auto handlers_and_nums = hana::zip(handlers, nums_ptr);
hana::for_each(handlers_and_nums, [](auto &handler_num) {
handler_num[0_c](*handler_num[1_c]);
});
另一种更 "traditional" 的方法是遍历一个范围。
这就像使用旧的 for 循环。
auto indices = hana::make_range(0_c, hana::length(handlers));
hana::for_each(indices, [&](auto i) {
handlers[i](nums[i]);
});
我有两个元组,一个包含值,另一个包含对这些值的操作。 现在我想对每个值应用相应的操作,代码越少越好 "overhead"。 类似于下面的简化示例。
#include <iostream>
#include <boost/hana.hpp>
namespace hana = boost::hana;
using namespace hana::literals;
struct ThinkPositive
{
void operator()(int &val) const
{
std::cout << "Think positive!\n";
val = std::abs(val);
}
};
struct Nice
{
void operator()(int &val) const
{
std::cout << val << " is nice!\n";
}
};
void numbers()
{
auto handlers = hana::make_tuple(Nice{}, ThinkPositive{});
auto nums = hana::make_tuple(5, -12);
auto handlers_and_nums = hana::zip(handlers, nums);
hana::for_each(handlers_and_nums, [](auto &handler_num) {
handler_num[0_c](handler_num[1_c]);
});
auto result = hana::transform(handlers_and_nums, [](const auto &handler_num) {
return handler_num[1_c];
});
hana::for_each(result, [](const auto num) {
std::cout << "got " << num << '\n';
});
}
int main()
{
numbers();
}
虽然上面的示例有效,但就地修改 nums 的内容会更好。
有没有办法就地修改 nums?
你可以使用 zip_with
,但它似乎违背了它的本质(它要求函数实际上 return 一些东西,但是你的运算符 ()
return 什么都没有:
auto special_compose = [](auto&& l, auto&& r){ l(r); return 0; };
hana::zip_with(special_compose, handlers, nums);
如果你可以让你的运营商 return 一些东西,你可以选择 lockstep
:
hana::fuse(hana::fuse(hana::lockstep(hana::always(0)))(handlers))(nums);
应该有类似 lockstep
的定义,但没有外部 f
调用,但我在文档中找不到任何内容。
更标准的解决方案(不符合您对尽可能少的代码开销的要求):
template<typename Fs, typename Params, size_t... is>
void apply_in_lockstep_impl(Fs&& fs, Params&& ps, std::index_sequence<is...>){
int x[] = { (fs[hana::integral_c<size_t,is>](ps[hana::integral_c<size_t,is>]),0)... };
}
template<typename Fs, typename Params>
void apply_in_lockstep(Fs&& fs, Params&& ps){
static_assert(hana::size(fs) == hana::size(ps), "");
apply_in_lockstep_impl(std::forward<Fs>(fs),
std::forward<Params>(ps),
std::make_index_sequence<decltype(hana::size(ps))::value>{});
}
但在调用站点它更漂亮:
apply_in_lockstep(handlers, nums);
正如评论中指出的那样,另一个间接级别也有帮助。 在这里,这意味着将序列转换为指针序列,通过指针修改原始值。
auto nums_ptr = hana::transform(nums, [](auto &num) { return # });
auto handlers_and_nums = hana::zip(handlers, nums_ptr);
hana::for_each(handlers_and_nums, [](auto &handler_num) {
handler_num[0_c](*handler_num[1_c]);
});
另一种更 "traditional" 的方法是遍历一个范围。 这就像使用旧的 for 循环。
auto indices = hana::make_range(0_c, hana::length(handlers));
hana::for_each(indices, [&](auto i) {
handlers[i](nums[i]);
});