我有一个名为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)> {}
);
}
我可以做些什么,不会涉及如此多的代码重复?
答案 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)...};
}
包扩展将按顺序扩展([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))...};
}