So I have some type X:
typedef ... X;
and a template function f:
class <typename T>
void f(X& x_out, const T& arg_in);
and then a function g:
void g(const X* x_array, size_t x_array_size);
I need to write a variadic template function h that does this:
template<typename... Args>
void h(Args... args)
{
constexpr size_t nargs = sizeof...(args); // get number of args
X x_array[nargs]; // create X array of that size
for (int i = 0; i < nargs; i++) // foreach arg
f(x_array[i], args[i]); // call f (doesn't work)
g(x_array, nargs); // call g with x_array
}
The reason it doesn’t work is because you can’t subscript args like that at runtime.
What is the best technique to replace the middle part of h?
And the winner is Xeo:
template<class T> X fv(const T& t) { X x; f(x,t); return x; }
template<class... Args>
void h(Args... args)
{
X x_array[] = { fv(args)... };
g(x_array, sizeof...(Args));
}
(Actually in my specific case I can rewrite f to return x by value rather than as an out parameter, so I don’t even need fv above)
You could refactor or wrap
fto return a newXinstead of having it passed, since this would play pack expansion into the hand and make the function really concise:Live example.
And if you could change
gto just accept anstd::initializer_list, it would get even more concise:Live example. Or (maybe better), you could also provide just a wrapper
gthat forwards to the realg:Live example.
Edit: Another option is using a temporary array:
Live example. Note that the
as_lvaluefunction is dangerous, the array still only lives until the end of the full expression (in this caseg), so be cautious when using it. TheAliasis needed since justX[]{ ... }is not allowed due to the language grammar.If all of that’s not possible, you’ll need recursion to access all elements of the
argspack.Live example.
Edit: Inspired by ecatmur’s comment, I employed the indices trick to make it work with just pack expansion and with
fandgas-is, without altering them.Live example.