Is this a perfect forwarding function? Or does the creation of a temporary T make it non-perfect? T is a trivial class.
template<class T, typename... Args>
void foo(Args&&... args)
{
bar(T{std::forward<Args>(args)...});
}
If it is a perfect forwarding function I expect it to incur no overhead, but creating a T must incur overhead unless a suitable optimisation is available to the compiler.
Perfect forwarding doesn't mean no overhead, and in current C++, perfect forwarding always has the potential to create undesired temporary objects. For example:
class C { C(int); };
void foo(C c);
template <class Arg>
void bar(Arg&& arg) {
foo(std::forward<Arg>(arg));
}
C getC();
int main() {
foo(getC());
bar(getC());
}
In the call foo(getC())
, guaranteed copy elision occurs, and the return statement in getC
constructs the C
object directly into the parameter c
of foo
, with no copies or moves taking place. In the call bar(getC())
, which uses perfect forwarding, the prvalue getC()
is materialized first in order to be bound to the reference parameter of bar
, and then the move constructor of C
is called in order to initialize c
from std::forward<Arg>(arg)
.
You might say that perfect forwarding isn't perfect.
Anyway, what "perfect forwarding" means, then, is that lvalues are forwarded as lvalues of the same type, and rvalues are forwarded as rvalues of the same type. In your original example, lvalues passed to foo
are forwarded as lvalues of the same type to the constructor of T
, and rvalues passed to foo
are forwarded as rvalues of the same type to the constructor of T
. So yes, you have perfect forwarding here.