Consider:
template <typename... Args>
void foo(Args... args) {
bar(std::forward<Args>(args)...);
}
template <typename... Args>
void foo2(Args&&... args) {
bar(std::forward<Args>(args)...);
}
I understand the perfect rvalue references forwarding in case of foo2
, but what is the purpose of forwarding the variadic argument values of foo
?
What would be different if foo
would look like this?
template <typename... Args>
void foo(Args... args) {
bar(args...);
}
CodePudding user response:
It's not the same thing.
In this
template <typename... Args>
void foo(Args... args) {
bar(std::forward<Args>(args)...);
}
Args
will never be deduced to be a reference (foo(Args...)
meansfoo
's taking the arguments by value, not by reference);- on the other hand
std::forward<T>(t)
is nothing more thanstatic_cast<T&&>(t)
, just with a more explicit intent from the programmer;
The two things together sum up to static_cast<Args&&>(args)...
having an rvalue reference return type, i.e. returning an rvalue (because Args
is not a reference, so no reference collapsing can occur between Args
and &&
to give an lvalue reference return type, which would mean an lvalue return value).
So no, there's no perfect forwarding in your first version of foo
. The std::forward
in it unconditionally casts its arguments to rvalues; and that's typically std::move
's job:
// this is equivalent to the code above
template <typename... Args>
void foo(Args... args) {
bar(std::move(args)...);
}