3

I have a function template:

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

I have a std::tuple that I want to unpack into args. My current solution is

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...>{});  
  ...
}

Note the artificial set_args_2() that is purely there to get Idx to unpack the tuple. Is there a way to unpack the tuple in-place func(), so that set_args() can be called directly?

Lingxi
  • 14,579
  • 2
  • 37
  • 93

1 Answers1

6

C++17 introduces std::apply:

std::apply([&](auto&&... args) { 
    set_args(p, std::forward<decltype(args)>(args)... );
}, args);
Holt
  • 36,600
  • 7
  • 92
  • 139
  • @Holt I just realised... `std::apply(set_args, std::tuple_cat(std;:forward_as_tuple(p), args))` should also work, but i don't know if it needs more perfect forwarding – Caleth Apr 20 '18 at 12:56
  • 1
    @Caleth This would not work directly since `set_args` is a templated function. – Holt Apr 20 '18 at 12:59
  • 1
    @Caleth It's actually even more complicated because `std::tuple_cat` would copy elements inside `args`, unless `args` contains reference, which would not work here because `args... ` is passed by reference in `set_args`. – Holt Apr 20 '18 at 13:01
  • The comment just revealed that the answer may actually be smarter than you thought. Bad I cannot up-vote twice. – Lingxi Apr 20 '18 at 13:33
  • Not sure why would this answer be accepted. Essentially it is the solution similar to OP's solution but not only implying use of "artificial layer for std::index_sequence", but also requiring an extra generic lambda. – user7860670 Jan 29 '20 at 20:14
  • @user7860670 I don't see your point... This obviously does exactly what OP does as the question is how to do it without the extra `set_args2`. The lambda is here to avoid having to define `set_args2` since you cannot pass `set_args` directly as `set_args` is templated, as explained in the previous comment. – Holt Jan 29 '20 at 20:17
  • `std::apply` is typically implemented invoking some sort of auxiliary function similar to `set_args2` but invoking a functor passed instead of hardcoded `set_args` function. Yeah, this way most of the boilerplate is hidden in the guts of standard library, but it does not help avoiding "artificial layer for std::index_sequence" or call `set_args` directly. – user7860670 Jan 29 '20 at 20:25
  • @user7860670 I see your point. You just interpret the question differently that I do (and probably OP as he accepted this answer). You obviously do not remove the layer in term of compilation time or runtime if the compiler does not optimize everything, but you do remove the need for a separate `set_args2`, which is probably the "layer" OP is referring to. – Holt Jan 29 '20 at 20:26