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

How to avoid using the "indices trick" repeatedly?

本文关键字:indices trick 何避免      更新时间:2023-10-16

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

对于这个类,我有一个std::unordered_map<std::string, memory_region> my_map- 用于在不共享标头的代码部分之间传递类型擦除的跨度,因此它们无法知道彼此的类型。对其中一个的典型访问如下所示:

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>()...
);
}

(这是臭名昭著的索引技巧的变体;请注意,相同的类型可能会在包中出现不止一次,所以我不能"将类型包装在元组中"并按类型访问它。

不过,问题是 - 我的代码在模板参数中没有该索引序列;其中大部分仅在类型的参数包上模板化。所以我发现自己一直在编写"辅助函数/方法"以便能够使用该索引序列,例如:

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)> {}
);
}

我能做什么,这不会涉及那么多的代码重复?

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

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)...};
}

演示

包扩展将按顺序扩展([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))...};
}

演示 2