为什么使用 std::forward 禁用模板参数推导?

时间:2023-03-08
本文介绍了为什么使用 std::forward 禁用模板参数推导?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

在 VS2010 中 std::forward 定义如下:

In VS2010 std::forward is defined as such:

template<class _Ty> inline
_Ty&& forward(typename identity<_Ty>::type& _Arg)
{   // forward _Arg, given explicitly specified type parameter
    return ((_Ty&&)_Arg);
}

identity 似乎仅用于禁用模板参数推导.在这种情况下故意禁用它有什么意义?

identity appears to be used solely to disable template argument deduction. What's the point of purposefully disabling it in this case?

推荐答案

如果将 X 类型的对象的右值引用传递给采用 T&& 类型的模板函数 作为其参数,模板参数推导推导出 TX.因此,参数的类型为 X&&.如果函数参数是左值或 const 左值,则编译器将其类型推导为该类型的左值引用或 const 左值引用.

If you pass an rvalue reference to an object of type X to a template function that takes type T&& as its parameter, template argument deduction deduces T to be X. Therefore, the parameter has type X&&. If the function argument is an lvalue or const lvalue, the compiler deduces its type to be an lvalue reference or const lvalue reference of that type.

如果 std::forward 使用模板参数推导:

If std::forward used template argument deduction:

由于带有名称的对象是左值,因此std::forward 唯一一次正确地转换为T&&参数是一个未命名的右值(如 7func()).在完美转发的情况下,您传递给 std::forwardarg 是一个左值,因为它有一个名称.std::forward 的类型将被推导出为左值引用或常量左值引用.引用折叠规则将导致 std::forward 中 static_cast 中的 T&& 始终解析为左值引用或常量左值引用.

Since objects with names are lvalues the only time std::forward would correctly cast to T&& would be when the input argument was an unnamed rvalue (like 7 or func()). In the case of perfect forwarding the arg you pass to std::forward is an lvalue because it has a name. std::forward's type would be deduced as an lvalue reference or const lvalue reference. Reference collapsing rules would cause the T&& in static_cast<T&&>(arg) in std::forward to always resolve as an lvalue reference or const lvalue reference.

示例:

template<typename T>
T&& forward_with_deduction(T&& obj)
{
    return static_cast<T&&>(obj);
}

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));
}

这篇关于为什么使用 std::forward 禁用模板参数推导?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!