Reputation: 2313
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?
Upvotes: 3
Views: 194
Reputation: 36802
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.
Upvotes: 6