Disabling Template Argument Deduction with std::forward to Ensure Correct Forwarding
Consider the definition of std::forward in VS2010:
template inline
_Ty&& forward(typename identity<_Ty>::type& _Arg)
{ // forward _Arg, given explicitly specified type parameter
return ((_Ty&&)_Arg);
}
The purpose of the identity template is to disable template argument deduction. Why is this crucial in this scenario?
Template argument deduction would lead to incorrect type deduction. If an rvalue reference to an object of type X is passed to a template function with a parameter type T&, template argument deduction would infer T as X, resulting in a parameter type X&. However, for perfect forwarding, the parameter is an lvalue because it has a name. Therefore, using template argument deduction in std::forward would cause the deduced parameter type to be an lvalue reference or const lvalue reference.
template
T&& forward_with_deduction(T&& obj)
{
return static_castConsider the following example:
void test(int&){}
void test(const int&){}
void test(int&&){}
template
void perfect_forwarder(T&& obj)
{
test(forward_with_deduction(obj));
}
int main()
{
int x;
const int& y(x);
int&& z = std::move(x);
test(forward_with_deduction(7)); // 7 is an int&&, correctly calls test(int&&)
test(forward_with_deduction(z)); // z is treated as an int&, calls test(int&)
// All the below call test(int&) or test(const int&) because in perfect_forwarder 'obj' is treated as
// an int& or const int& (because it is named) so T in forward_with_deduction is deduced as int&
// or const int&. The T&& in static_cast<T&&>(obj) then collapses to int& or const int& - which is not what
// we want in the bottom two cases.
perfect_forwarder(x);
perfect_forwarder(y);
perfect_forwarder(std::move(x));
perfect_forwarder(std::move(y));
}
In this example, perfect forwarding fails because the parameter in perfect_forwarder is treated as an lvalue or const lvalue reference due to its name. This leads to incorrect type deduction in forward_with_deduction, resulting in undesired static_cast semantics.
Disabling template argument deduction with the identity template in std::forward ensures that std::forward always returns an rvalue reference, which is essential for correct perfect forwarding of lvalues as well as rvalues.
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3