Disabling Template Argument Deduction with std::forward to Ensure Correct Forwarding
Consider the definition of std::forward in VS2010:
<code class="cpp">template<class _Ty> inline _Ty&& forward(typename identity<_Ty>::type& _Arg) { // forward _Arg, given explicitly specified type parameter return ((_Ty&&)_Arg); }</code>
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.
<code class="cpp">template<typename T> T&& forward_with_deduction(T&& obj) { return static_cast<T&&>(obj); }</code>
Consider the following example:
<code class="cpp">void test(int&){} void test(const int&){} void test(int&&){} template<typename T> 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)); }</code>
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.
The above is the detailed content of Why does std::forward use the identity template to disable template argument deduction?. For more information, please follow other related articles on the PHP Chinese website!