Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Syntax differences in variadic template parameter pack forwarding

While working with variadic templates I have come across two different ways of writing a call to std::forward, but I am left wondering what the actual difference between the two syntaxes?

template<typename... T>
void one(T&&... args)
{
    foo(std::forward<T&&...>(args...));
}
template<typename... T>
void two(T&&... args)
{
    foo(std::forward<T&&>(args)...);
}

According to my compilers these are both valid syntax, and in most cases the compiler does not complain. But I have found some cases where one or the other is correct but the compiler does not say why in detail.

Is one more correct that the other?
Do they serve different purposes?

like image 688
Alex Zywicki Avatar asked Dec 07 '25 18:12

Alex Zywicki


1 Answers

The ... placement tells the compiler where to expand the pack, once for each element in the thing before it (hard to phrase easily but I'll illustrate below).

Let's consider a pack T = {int, double, char} and args = {1, 2.0, '3'}

Your first example (one) will expand T inside of the <> and then args inside of the () so it becomes

foo(std::forward<T&&...>(args...));  // becomes:
foo(std::forward<int&&, double&&, char&&>(1, 2.0, '3'));

This is not how std::forward works since it only expects one argument. Your second example (two) says to expand the whole call to std::forward once for each item in the packs, so it becomes

foo(std::forward<T&&>(args)...);  // becomes:
foo(std::forward<int&&>(1), std::forward<double&&>(2.0),std::forward<char&&>('3'));

As for why these both compiled fine, the result is identical if you called with only one argument. If you never called it at all then it wouldn't be instantiated.

like image 175
Ryan Haining Avatar answered Dec 09 '25 15:12

Ryan Haining



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!