Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ std::forward与std::move的用法_C++_C++11_Move_Forward - Fatal编程技术网

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类型的右值调用<