I set up a test case to learn about perfect forwarding.
std::string inner(const std::string& str ) {
return "const std::string&";
}
std::string inner(std::string& str ) {
return "std::string&";
}
std::string inner(const std::string&& str ) {
return "const std::string&&";
}
std::string inner(std::string&& str ) {
return "std::string&&";
}
template <typename T> void outer(T&& t) {
std::cout << "t: " << t << std::endl;
std::cout << "perfect forward: " << inner(std::forward<T>(t)) << std::endl;
std::cout << std::endl;
}
void PerfectForwarding()
{
outer("literal");
outer(lvalue);
outer(constlvalue);
outer(rvalue());
outer(constrvalue());
}
std::forward
works as expected. The interesting behavior emerges when I implement my own forward function without identity:
template <typename T> T&& MyForward(T& t)
{
return ((T&&)t);
}
Replacing std::forward
with MyForward
in outer gives the exact same result! The behavior begs the question why identity is used?
Compiler VS2010
Update 1: In reference to preventing type deduction
AFAIK, the special type deduction rule is only activated on T&&. Note the definition of forward, forward(typename identity<T>::type& t)
. The argument type has only one &. In fact, after I changed MyForward to use identity, and leave out the (T&&) casting, the example does not compile. On the surface, the casting from lvalue to rvalue seems to make the forward work.
Update 2: tested on ideone.com with GCC 4.5, same behavior.
std::forward helps to implement perfect forwarding. This mechanism implies that objects passed to the function as lvalue expressions should be copied, and objects passed to the function as rvalue expressions should be moved. If you assign an rvalue reference to some ref variable, then ref is a named entity.
std::move takes an object and casts it as an rvalue reference, which indicates that resources can be "stolen" from this object. std::forward has a single use-case: to cast a templated function parameter of type forwarding reference ( T&& ) to the value category ( lvalue or rvalue ) the caller used to pass it.
What is Perfect Forwarding. Perfect forwarding allows a template function that accepts a set of arguments to forward these arguments to another function whilst retaining the lvalue or rvalue nature of the original function arguments.
remove_reference<T>
(identity
was in an old version of the draft, but was changed to remove_reference
) is used to prevent type deduction: std::forward
only works with an explicit type parameter. Otherwise the following would compile:
std::forward(t)
... but it would not do the right thing.
Regarding the issue with lvalues/rvalues, please do notice that there are two overloads of std::forward
: one for lvalues, another for rvalues.
In fact, the MyForward
implementation given is more like std::move
: it turns lvalues into rvalues (the difference is that move accepts rvalues as well).
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