Consider the following code:
#include <string>
auto f1(auto&& v) {
return v;
}
auto f2(auto&& v) {
return std::forward<decltype(v)>(v);
}
int main() {
return f1(std::string("hello")).size() + f2(std::string("hello")).size();
}
clang will generate the same assembly code for f1
and f2
. However,
As per the C++ core guidelines, f2
is recommended;
As per p0527r1, f1
is enough since C++23.
It's possible that f2
has an extra function call than f1
. We should not depend on the compiler to optimize that out; even if it almost always does.
Should we still always std::forward
a universal reference argument? or the C++ core guidelines should be updated?
You should use std::forward
with universal (forwarding) references when perfect forwarding is actually required, typically when passing the parameter to another function or constructor that depends on value category (e.g., distinguishing between lvalue/rvalue overloads or enabling move semantics).
In your example, both f1
and f2
return the parameter, and auto
return type triggers move semantics for rvalues anyway due to return value optimization (RVO), so is not strictly necessary here. However, using it is good practice in generic code because it preserves the value category and avoids surprises if the function is later changed to forward its argument.