I'm reading the reference collapsing rules and I have a question: why if I pass a rvalue A to
template<typename T>
void foo(T&&);
T is deduced to be A?
e.g. if I pass std::string()
to the function T
is deduced to be std::string
, why not std::string&&
? It would have made more sense to me, what's the rationale behind deducing T
to the type itself?
I understand that a forwarding reference is "an rvalue reference to a cv-unqualified template parameter", such as in. template <class T> void foo(T&& ); which means the above function can take both l-value and r-value reference.
Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higer performance and more robust libraries.
An lvalue reference can bind to an lvalue, but not to an rvalue.
A forwarding reference is an rvalue reference to a cv-unqualified template parameter. If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction. Hence, the two mean the same thing, and the current C++ standard term is forwarding reference.
This merely lines up with what we expect in general from template type deduction:
template <class T> void vfoo(T );
template <class T> void lfoo(T& );
template <class T> void cfoo(T const& );
template <class T> void ffoo(T&& );
std::string x;
vfoo(x); // deduce T = std::string
lfoo(x); // deduce T = std::string
cfoo(x); // deduce T = std::string
ffoo(x); // deduce T = std::string& !
ffoo(std::move(x)); // deduce T = std::string
From the original paper, emphasis mine:
When deducing a function template type using an lvalue argument matching to an rvalue reference, the type is deduced as an lvalue reference type. When deduction is given an rvalue argument, type deduction proceeds just as with other types.
It's the lvalue deduction case that's the exceptional one, which is why it gets an extra sentence in the type deduction rules. The rvalue case is typical - it lines up with the simple mental model of pasting in the deduced types to see what function you end up with. Called T&&
with a std::string
? Get T = std::string
so that the argument reads std::string&&
. Check.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With