如何避免使用" indices trick"反复?

时间:2017-08-22 09:22:27

标签: c++ c++14 variadic-templates idiomatic index-sequence

我有一个名为memory_region的类,它有点像无类型gsl::span(即它本质上是void*size_t),其中我也用于类型擦除。因此它具有as_span<T>()方法。

通过这个课程,我有一个std::unordered_map<std::string, memory_region> my_map - 用于在代码中不共享标题的部分之间传递类型删除的跨度,因此他们无法了解彼此和#39;类型。对其中一个的典型访问看起来像:

auto foo = my_map.at("foo").as_span<bar_t>();

这适用于具有一组固定缓冲区和类型及名称的代码。但是 - 当我的代码缓冲区依赖于模板参数包时,事情会变得棘手。现在,我已经实现了

std::string input_buffer_name(unsigned input_buffer_index);

函数,所以如果我有一个索引序列和我的参数包我可以做,例如

template<typename Ts..., std::size_t... Indices>
my_function(std::unordered_map<std::string, memory_region>& my map) {
    compute_stuff_with_buffers(
        my_map.at(input_buffer_name(Indices)).as_span<Ts>()...
    );
}

(这是对臭名昭着的indices trick的变体;请注意,相同的类型可能会在包中出现多次,因此我无法将这些类型包装在元组中&#34 ;并按类型访问。)

但问题是 - 我的代码在模板参数中没有索引序列;其中大部分都是模板参数包的模板。所以我发现自己正在编写&#34;辅助函数/方法&#34;所有时间都能够使用该索引序列,例如:

template<typename Ts..., std::size_t... Indices>
my_function_helper(
    std::unordered_map<std::string, memory_region>& my map
    std::index_sequence<Indices...>  /* unused */) 
{
    compute_stuff_with_buffers(
        my_map.at(input_buffer_name(Indices)).as_span<Ts>()...
    );
}

template<typename Ts...>
my_function(std::unordered_map<std::string, memory_region>& my map) {
    my_function_helper(
        my_map, std::make_index_sequence<sizeof...(Ts)> {}
    );
}

我可以做些什么,不会涉及如此多的代码重复?

1 个答案:

答案 0 :(得分:2)

在这种情况下,您可以使用数组形式的简单包扩展:

template<typename... Ts>
void my_function(std::unordered_map<std::string, memory_region>& my_map) {
    using swallow = int[];
    unsigned i = 0;
    (void)swallow{0, (my_map.at(input_buffer_name(i++)).as_span<Ts>(), 0)...};
}

Demo

包扩展将按顺序扩展([temp.variadic]),并按顺序(从左到右)进行评估,因为我们正在使用支撑初始化列表(未使用的整数数组):[dcl.init。 aggr]

  

当初始化列表[...]初始化聚合时,初始化列表的元素将按顺序作为聚合元素的初始值设定项。

回复:

  

但是如果我需要两次使用input_buffer_name(i)怎么办?例如如果我需要使用   { input_buffer_name(index), my_map.at(input_buffer_name(index).as_span<Ts>()) }

我想我们可以利用逻辑AND将从左到右排序([expr.log.and])的事实,并且布尔值也可以提升为int

template<typename... Ts>
void my_function_v2(std::unordered_map<std::string, memory_region>& my_map) {
    using swallow = int[];
    unsigned i = 0;
    (void)swallow{0, ((std::cout<< input_buffer_name(i) << std::endl, true) && (my_map.at(input_buffer_name(i++)).as_span<Ts>(), true))...};
}

Demo 2