使用std :: forward和std :: move
我总是读std::forward
只能用于模板参数。 但是,我在问自己为什么。 看下面的例子:
void ImageView::setImage(const Image& image){ _image = image; } void ImageView::setImage(Image&& image){ _image = std::move(image); }
这两个function基本上是一样的; 一个采取一个l值参考,另一个r值参考。 现在,我认为自从std::forward
应该返回一个l值引用,如果参数是一个l值引用和一个r值引用,如果参数是一个,这个代码可以简化为这样的:
void ImageView::setImage(Image&& image){ _image = std::forward(image); }
这是类似的例子cplusplus.com提到了std::forward
(只是没有任何模板参数)。 我只想知道,如果这是正确的,或者不是,为什么。
我也在问自己究竟会有什么不同
void ImageView::setImage(Image& image){ _image = std::forward(image); }
你不能使用std::forward
而不明确指定它的模板参数。 它被有意使用在一个非推断的上下文中。
为了理解这一点,你需要真正理解转发引用( T&&
对于推导出的T
)是如何在内部工作的,而不是把它们当作“魔法”。 所以让我们来看看。
template <class T> void foo(T &&t) { bar(std::forward<T>(t)); }
比方说,我们这样称呼foo
:
foo(42);
42
是int
types的右值。 T
被推断为int
。 因此,对bar
的调用使用int
作为std::forward
的模板参数。 std::forward<U>
的返回types是U &&
。 在这种情况下,这是int &&
,所以t
被作为右值转发。
现在,让我们调用foo
像这样:
int i = 42; foo(i);
i
是一个int
types的左值。 由于完美转发的特殊规则,当V
types的左值被用来在T &&
types的参数中推导T
时, V &
被用于推导。 因此,在我们的例子中, T
被推断为int &
。
因此,我们指定int &
作为std::forward
的模板参数。 因此它的返回types是“ int & &&
”,它被折叠为int &
。 这是一个左值,所以i
作为左值转发。
概要
为什么这与模板一起工作是当你做std::forward<T>
, T
有时是一个引用(当原始文件是一个左值),有时不是(当原文是右值时)。 因此, std::forward
将根据需要转换为左值或右值引用。
您无法精确地在非模板版本中进行这项工作,因为您只能使用一种types。 更不用说setImage(Image&& image)
根本就不接受左值的事实 – 左值不能绑定右值引用。
我推荐阅读“Effective Modern C ++”,其作者是Scott Meyers 。
第23项:了解std :: move和std :: forward。
项目24:区分右值引用的通用引用。
从纯粹的技术angular度来看,答案是肯定的: std :: forward可以做到这一切。 std :: move是没有必要的。 当然,这两个function都不是真的有必要,因为我们可以在任何地方写剧本,但是我希望我们也同意这样做。 标准::移动的景点是方便,减less错误的可能性,更清晰 。
rvalue-reference :这个函数接受rvalues不能接受左值。
void ImageView::setImage(Image&& image){ _image = std::forward(image); //error _image = std::move(image);//conventional _image = std::forward<Image>(image);//unconventional }
请注意,std :: move只需要一个函数参数,而std :: forward需要函数参数和模板types参数。
template <typename T> void ImageView::setImage(T&& image){ _image = std::forward<T>(image); }
通用参考(转发参考) :该function接受所有参数,并完成转发。
您必须在std::forward
指定模板types。
在这种情况下, Image&& image
总是一个r值引用, std::forward<Image>
将总是移动,所以你不妨使用std::move
。
你的函数接受一个r值引用不能接受l值,所以它不等于前两个函数。