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

Why is template argument deduction disabled with std::forward?(为什么使用 std::forward 禁用模板参数推导?)
本文介绍了为什么使用 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 禁用模板参数推导?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

How do compilers treat variable length arrays(编译器如何处理变长数组)
Deduce template argument from std::function call signature(从 std::function 调用签名推导出模板参数)
check if member exists using enable_if(使用 enable_if 检查成员是否存在)
Standard Library Containers with additional optional template parameters?(具有附加可选模板参数的标准库容器?)
Uses of a C++ Arithmetic Promotion Header(C++ 算术提升标头的使用)
Parameter pack must be at the end of the parameter list... When and why?(参数包必须位于参数列表的末尾...何时以及为什么?)