Вы можете использовать трюк с указанием std::function
, чтобы вытащить аргументы, но вы действительно не хотите фактически создавать a std::function
. Вы хотите сложить в лямбда-стране. std::function
добавляет накладные расходы и распределение из-за стирания типа - но вы ничего не делаете, если вам действительно нужны преимущества, которые обеспечивает стирание типа. Это все потеря и нет победы. На самом деле не получается std::function
.
Тем не менее, вам, конечно, все еще нужны аргументы. Таким образом, вы можете сделать это:
template <typename T> struct type { };
template <typename F>
void get(size_t index, F f) {
using function_type = decltype(std::function(f));
get_impl(index, f, type<function_type>{});
}
По сути, мы берем некоторый вызываемый объект - и затем выводим из него std::function
. Это дает нам некоторый тип. В конкретном примере в OP этот тип - std::function<void(comp_a&, comp_b&)>
. Затем мы просто перенаправляем этот тип в другую функцию - как пустой объект. Нет накладных расходов. Повторим, мы на самом деле не создаем std::function
- мы просто передаем его тип.
Эта другая функция может воспользоваться тем, что знает std::function
:
template <typename T> using uncvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
template <typename F, typename R, typename... Args>
void get_impl(size_t index, F f, type_t<std::function<R(Args...)>>) {
f(std::get<uncvref_t<Args>::id>(components)[index] ...);
}
Вам нужен uncvref_t
там для обработки случая, когда Args
может быть или не быть ссылкой или cv -качественным.
Теперь, это не будет работать для любого вызываемого. Если вы передадите общую лямбду, вывод std::function
не удастся. Но тогда ... это не могло сработать, так что это не большая потеря?