[英]Use of std::forward in c++
我遇到过一个代码,其中使用了std::forward
。 我已经搜索了很长时间,并且无法理解它的真实目的和用途。
我在stackoverflow中看到了类似的线程,但仍然不清楚。 有人可以用一个简单的例子解释一下吗?
PS:我已经浏览了这个页面 ,但仍然无法欣赏它的使用。 请不要将此问题标记为重复,而是尝试帮助我。
当你链接的页面构成它:
这是一个辅助函数,可以完美地转发作为对推导类型的rvalue引用的参数,保留所涉及的任何潜在的移动语义。
当你有一个命名值时 ,如
void f1(int& namedValue){
...
}
或者在
void f2(int&& namedValue){
...
}
无论如何,它都会评估 lvalue
。
更进一步。 假设你有一个模板功能
template <typename T>
void f(T&& namedValue){
...
}
这样的函数可以用左值或右值调用; 但是,无论如何,namedValue都会评估为lvalue
。
现在假设您有两个辅助函数重载
void helper(int& i){
...
}
void helper(int&& i){
...
}
从f
里面调用helper
template <typename T>
void f(T&& namedValue){
helper(namedValue);
}
将总是调用helper
的第一个重载,因为namedValue
是一个命名值 ,当然,它会计算为lvalue
。
为了在适当的时候调用第二个版本(即当用rvalue参数调用f
时),你写
template <typename T>
void f(T&& namedValue){
helper( std::forward<T>(namedValue) );
}
以下所有这些都在文档中非常简明扼要地表达出来
对这个函数的需求源于这样一个事实,即所有命名值(例如函数参数)总是作为左值(甚至是那些被声明为右值引用的值)进行评估,这在保留模板函数上的潜在移动语义方面存在困难,模板函数将参数转发给其他函数。
每个表达式恰好是以下两个值类别之一:左值或右值。
通常,如果你调用如下函数:
template<typename T>
void f(T t);
template<typename T>
void g(T t)
{
f(t);
}
g
的参数的值类别在调用g和f之间丢失,因为命名参数(如局部变量)总是lvalues。
通过使用std::forward
并将参数调整为使用引用折叠的“通用引用”,您可以保留值类别:
template<typename T>
void f(T&& t);
template<typename T>
void g(T&& t)
{
f(forward<T>(t));
}
这就是为什么它被称为“前进”,因为你正在“转发”价值类别,而不是失去它。
因此,在示例中,如果使用rvalue调用g
,则将使用rvalue调用f - 而不是左值。
它用于在将模板传递给另一个函数时保留模板中参数的确切类型。 例如:
template<class T>
void wrapper(T&& arg)
{
foo(std::forward<T>(arg)); // Forward a single argument.
}
其工作原理如下:
如果函数wrapper
获取std::string
或const std::string&
,则调用foo
就好像arg
具有const std::string&
。
如果函数wrapper
获取std::string&
,则调用foo
就好像arg
具有std::string&
类型一样。
如果函数wrapper
获取std::string&&
,则调用foo
就好像arg
具有std::string&&
类型。
std::forward
解决的问题是通过常规规则,函数中的arg
类型是std::string
即使我们将std::string&&
传递给wrapper
。 std::forward
允许向调用站点注入实际类型的T
,即T
, T&
, const T&
或T&&
。
它的基本用途是你在函数g
中被称为这样:
g(T1 p1, T2 p2, /* ... */);
并且您想要使用完全相同的类型调用函数f
:
f(T1 p1, T2 p2, /* ... */);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.