C++ std::forward与std::move的用法
我总是读到C++ std::forward与std::move的用法,c++,c++11,move,forward,C++,C++11,Move,Forward,我总是读到std::forward仅用于模板参数。然而,我问自己为什么。请参见以下示例: void ImageView::setImage(const Image& image){ _image = image; } void ImageView::setImage(Image&& image){ _image = std::move(image); } 这两个功能基本相同;一个取l值参考,另一个取r值参考。现在,我想既然std::forward应该返
std::forward
仅用于模板参数。然而,我问自己为什么。请参见以下示例:
void ImageView::setImage(const Image& image){
_image = image;
}
void ImageView::setImage(Image&& image){
_image = std::move(image);
}
这两个功能基本相同;一个取l值参考,另一个取r值参考。现在,我想既然std::forward
应该返回一个l值引用,如果参数是l值引用,则返回一个r值引用,如果参数是一个,则返回一个l值引用,那么这段代码可以简化为如下内容:
void ImageView::setImage(Image&& image){
_image = std::forward(image);
}
foo(42);
int i = 42;
foo(i);
这与cplusplus.com在std::forward
中提到的示例类似(只是没有任何模板参数)。我只是想知道,这是否正确,如果不正确,为什么
我也在问自己,到底有什么不同
void ImageView::setImage(Image& image){
_image = std::forward(image);
}
您必须在
std::forward
中指定模板类型
在此上下文中,
Image&&Image
始终是一个r值引用,std::forward
将始终移动,因此您不妨使用std::move
接受r值引用的函数不能接受l值,因此它不等同于前两个函数。如果不明确指定其模板参数,则不能使用std::forward
。它是在非推断上下文中故意使用的
要理解这一点,您需要真正了解转发引用(T&&
对于导出的T
)是如何在内部工作的,而不是像“这很神奇”一样将它们挥走。因此,让我们来看看这一点
template <class T>
void foo(T &&t)
{
bar(std::forward<T>(t));
}
是42
类型的右值int
被推断为T
int
- 因此,对
的调用使用bar
作为int
的模板参数std::forward
的返回类型是std::forward
(在本例中,即U&
),因此int&
作为右值转发t
foo
:
void ImageView::setImage(Image&& image){
_image = std::forward(image);
}
foo(42);
int i = 42;
foo(i);
是i
类型的左值int
- 由于完美转发的特殊规则,当使用
类型的左值在V
类型的参数中推断T&
时,将使用T
进行推断。因此,在我们的例子中,V&
被推断为T
int&
int&
作为std::forward
的模板参数。因此,它的返回类型将是“int&&&&
”,它将折叠为int&
。这是一个左值,因此i
作为左值转发
摘要
这对模板起作用的原因是当您执行
std::forward
时,T
有时是一个引用(当原始值是左值时),有时不是(当原始值是右值时)<因此,code>std::forward将根据需要转换为左值或右值引用
您不能在非模板版本中完全执行此操作,因为您只有一种类型可用。更不用说,setImage(Image&&Image)
根本不接受左值,因为左值不能绑定到右值引用。我建议阅读Scott Meyers的《有效的现代C++》,特别是:
- 项目23:理解
和std::move
std::forward
- 第24项:区分通用引用和右值引用
std::forward
可以全部完成。std::move
不是必需的。当然,两者都不起作用
真的很有必要,因为我们可以到处写演员,但我
希望我们同意这会很恶心std::移动
的景点
方便快捷,减少出错的可能性,更清晰
右值参考
此函数接受右值,不能接受左值
void ImageView::setImage(Image&& image){
_image = std::forward(image); // error
_image = std::move(image); // conventional
_image = std::forward<Image>(image); // unconventional
}
要真正理解,请观看以下视频:问题:Forward不会根据其参数返回左值引用或右值引用。事实上,它完全忽略了参数的值类别。这是否回答了您的问题
std::forward
仅在用作std::forward
或std::forward
时才会移动,但并不总是像您所使用的那样say@PiotrS. 你是对的,我把事情简单化了。希望这样更好。“通用参考”的正式名称正在转发reference@JonathanWakely-谢谢,我明白了。@JonathanWakely:“通用参考”的官方名称现在正在转发参考”-我没有收到备忘录。从什么时候开始?在哪里宣布的?谢谢。J.J.N.萨特也在CPPCON 2014上讨论过,而最新版本的C++也提到了Irr。谢谢,作为参考,转发参考定义在OK的4.82.2.3中,我想我已经理解了。我想知道的是:我可以用l值引用和r值引用调用函数template void foo(T&&T)
?如果它是一个左值引用,T被推断为V&
,这意味着参数类型变成(V&&&&&&
,这基本上是一个对左值引用的rvlaue引用(或者什么?)?因此,这是一个行为不同于非模板函数的点,其中函数void foo(MyType&&t)
只能通过r值引用调用?@user1488118存在引用折叠规则T&&&
折叠为T&
,所有其他(T&&&
,T&&&
和T&&
)折叠为T&
是的,V&
的推导允许您使用左值和右值(不一定是引用)调用函数模板。获取Image&
的非模板函数只能使用Image类型的右值调用<