Распаковать std:: Кортеж на месте без искусственного слоя для последовательности std:: index


У меня есть шаблон функции:

template <typename... Us>
void set_args(const void* p, Us&... args);

У меня есть std::tuple, который я хочу распаковать в args. Мое текущее решение -

template <typename... Us, std::size_t... Idx>
void set_args_2(
 const void* p, std::tuple<Us...>& args, std::index_sequence<Idx...>) {
  set_args(p, std::get<Idx>(args)...);  
}

template <typename... Us>
void func(std::tuple<Us...>& args, ...) {
  ...
  set_args_2(p, args, std::index_sequence_for<Us...>{});  
  ...
}
Обратите внимание на искусственный set_args_2(), который существует исключительно для того, чтобы получить Idx, чтобы распаковать кортеж. Есть ли способ распаковать Кортеж на месте func(), Чтобы set_args() можно было вызвать напрямую?
2 2

2 ответа:

C++17 вводит std:: apply:

std::apply([&](auto&&... args) { 
    set_args(p, std::forward<decltype(args)>(args)... );
}, args);

Бессовестно воруя у Yakk, мы определяем некоторые вспомогательные функции

template<std::size_t... Is>
auto index_over(std::index_sequence<Is...>)
{
    return [](auto&& f) -> decltype(auto) {
        return decltype(f)(f)(std::integral_constant<std::size_t, Is>{}...);
    };
}

template<std::size_t N>
auto index_upto(std::integral_constant<std::size_t, N> = {})
{
    return index_over(std::make_index_sequence<N>{});
}

И вся распаковка может быть выполнена inline

template<typename... Ts>
void func(std::tuple<Ts...>& tup)
{
    index_upto<sizeof...(Ts)>()(
        [&](auto... Is) {
            set_args(p, std::get<Is>(tup)...);
        }
    );
}