3

我有两个元组,一个包含值,另一个元组包含这些值的操作。现在我想对每个值应用相应的操作,尽可能少的代码“开销”。类似于下面的简化示例。

#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 到位?

4

1 回答 1

3

您可以使用zip_with,但它似乎违背了它的本质(它需要函数实际返回某些内容,但您的运算符()什么也不返回:

auto special_compose = [](auto&& l, auto&& r){ l(r); return 0; };
hana::zip_with(special_compose, handlers, nums);

演示


如果你可以让你的运营商返回一些东西,你可以选择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 &num; });
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]);
});

演示


另一种更“传统”的方法是迭代一个范围。这就像使用旧的 for 循环。

auto indices = hana::make_range(0_c, hana::length(handlers));
hana::for_each(indices, [&](auto i) {
    handlers[i](nums[i]);
});

演示

于 2016-11-05T21:53:14.953 回答