I have a class named memory_region
, which is sort of like an untyped gsl::span
(i.e. it's essentially a void*
and a size_t
), which I also use for type erasure. It thus has an as_span<T>()
method.
With this class, I have a std::unordered_map<std::string, memory_region> my_map
- which is used to pass type-erased spans between parts of my code which don't share headers, so they can't know about each others' types. The typical access to one of these looks like:
auto foo = my_map.at("foo").as_span<bar_t>();
This works just fine with code that has a fixed set of buffers and types and names. But - things get tricky when my code's buffers depend on a template parameter pack. Now, I've implemented a
std::string input_buffer_name(unsigned input_buffer_index);
function, so if I have an index sequence and my parameter pack I can do, for example
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>()...
);
}
(this is a variation on the infamous indices trick; note that the same type may appear more than once in the pack, so I can't "wrap the types in a tuple" and acces it by type.)
The thing is, though - my code doesn't have that index sequence in the template parameters; most of it is templated on just the parameter pack of types. So I find myself writing "helper functions/methods" all the time to be able to use that index sequence, e.g.:
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)> {}
);
}
What can I do instead, that will not involve so much code duplication?