Как избежать использования «трюка с индексами»? несколько раз?

У меня есть класс с именем 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)> {}
);
}

Что я могу сделать вместо этого, что не будет так много дублировать код?

4

Решение

В этом случае вы можете использовать простое расширение пакета в виде массива:

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]

Когда агрегат инициализируется списком инициализаторов […], элементы списка инициализаторов берутся в качестве инициализаторов для элементов агрегата по порядку.


Re:

Но что, если мне нужно использовать input_buffer_name (i) дважды? например если мне нужно использовать
{ input_buffer_name(index), my_map.at(input_buffer_name(index).as_span<Ts>()) }

Я полагаю, мы могли бы воспользоваться тем фактом, что логическое И будет последовательно слева направо ([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

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]