首页 > 其他分享 >关于完美转发中forward的作用的一点理解

关于完美转发中forward的作用的一点理解

时间:2023-04-30 10:35:15浏览次数:43  
标签:std const 右值 完美 左值 && 转发 forward fn

 

首先先描述一下C++中各种类型的值(以下无特殊说明“类型”皆按如下分法)
lvalue(left value)左值:有标识符,且不能被回收
rvalue(right value)右值:有无标识符皆可,可以被回收
glvalue(generalized left value)泛左值:有标识符,可不可被回收皆可
prvalue(pure right value)纯右值:没有标识符,且可以被回收
xvalue - X值:有标识符,且可以被回收
(还有一些特殊的类型,不过对理解forward帮助不大)

当存在fn(X &); fn(X &&);fn(const X&);几种函数定义时,编译器会根据传入值所属的类型传给对应的函数执行:

左值(非const)优先找fn(X &),若没有找到,则再寻找fn(const X&),若还没有则报错
右值类似,优先找fn(X &&),其次fn(const X&)
const左值则只能找fn(const X&)
struct X {};

// overloads
void fn(X &) { std::cout<< "X &\n"; }
void fn(const X &) { std::cout<< "const X &\n"; }
void fn(X &&) { std::cout<< "X &&\n"; }

int main()
{
X a;
fn(a);
// lvalue selects fn(X &)
// fallbacks on fn(const X &)

const X b;
fn(b);
// const lvalue requires fn(const X &)

fn(X());
// rvalue selects fn(X &&)
// and then on fn(const X &)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
还存在其他的情况没有完全列出,总之编译器会根据值的类型根据参数值类型按一定规则寻找相应的函数执行

到了模板这里也有类似的情况:

template<typename T>
void foo(T &&); // forwarding reference here
// T is a template parameter for foo
1
2
3
如果这样定义一个模板,根据传入的参数的类型不同,会调用不同的模板实例进行计算,如传入左值则调用foo(T&);传入右值则调用foo(T&&);

而forward主要解决了这样的一个问题:
右值引用作为一种引用,也是一个左值
如果一个函数接受的是T&&这种参数,在该函数体内如果希望用接收到的这个右值引用参数去调用另一个需要右值引用参数的函数是调用不到的,比如:

void reference(int& v) {
std::cout <<"lvalue" << std::endl;
}
void reference(int&& v) {
std::cout <<"rvalue" << std::endl;
}
template <typename T>
void pass(T&& v) {
reference(v);
}
int main() {
std::cout <<"rvalue pass:";
pass(1);

std::cout <<"lvalue pass:";
int p = 1;
pass(p);

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
输出为:

rvalue pass:lvalue
lvalue pass:lvalue
1
2
在pass(1)的情况下,pass(T&& v)被实例化为pass(int&& v),在pass函数内用这个右值引用(类型为左值)只能调用到reference(int& v),右值引用本身是一个左值

修改代码为:

template <typename T>
void pass(T&& v) {
reference(std::forward<T>(v));
}
1
2
3
4
用forward()就能将右值引用(一个左值)转换为右值(xvalue)

forward能够将右值引用和左值引用(均为lvalue)区分出来(利用引用折叠的机制),然后相应地调用static_cast<T&>()转换为lvalue,或static_cast<T&&>()转换为rvalue

参考文章:C++ std::move and std::forward
————————————————
版权声明:本文为CSDN博主「MCCreeper」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/MCCreeper/article/details/129145074

 

标签:std,const,右值,完美,左值,&&,转发,forward,fn
From: https://www.cnblogs.com/im18620660608/p/17364971.html

相关文章

  • nginx 转发
    server{listen80;#listen443ssl;server_name*.*.com;#rewrite^(.*)$https://$host$1permanent;gzipon;gzip_staticon;#需要http_gzip_static_module模块gzip_min_length1k;gzip_comp_level4;gzip_proxiedany;......
  • Qt音视频开发42-网络推流(视频推流/本地摄像头推流/桌面推流/网络摄像头转发推流等)
    一、前言上次实现的文件推流,尽管优点很多,但是只能对现在存在的生成好的音视频文件推流,而现在更多的场景是需要将实时的视频流重新推流分发,用户在很多设备比如手机/平板/网页/电脑/服务器上观看,这样就可以很方便的将分散的视频流统一集中的流媒体服务器上,然后统一对外分发视频,而不......
  • 很实用(极少使用的词)的键盘消息转发(热键间接设置程序) [有代码]
    有些重复的点击是需要做的.但是有时这些点击是不需要看着操作.所以把该窗口切换到前台再去点击让我te不爽.于是写了这么个东西来方便方便.比如我自己写的试听清风网站的dj音乐这种东西.是需要发现这个歌曲不好听就换下首的,直到找到我喜欢的歌曲才去看它一下,那么这个程序可以帮我......
  • 子线程启动tkinter并完美退出
    importsysfromtkinterimport*fromPILimportImage,ImageTkfromthreadingimportThreaddefui():myPic=Nonedefopenimg():globalmyPicimg=Image.open("img.png")myPic=ImageTk.PhotoImage(img)......
  • 4.4 网际协议:因特网中的转发和编址
    一、IPv4数据报格式 1.版本号:4bit 2.首部长度:4bit,用于确定IP数据报中载荷实际开始的地方。一般IP数据报首部长度为20字节。 3.服务类型 4.数据报长度:16bit,IP数据报的总长度(首部+数据),单位为字节。 5.16比特标识,3比特标志,13比特片偏移:与分片有关 6.寿命:每过一台......
  • sql.SQLException: 对只转发结果集的无效操作: absolute,可滚动结果集
    获得ResultSet的长度可以使用getRow,但是首先要设置ResultSet为可滚动结果集,否则会报java.sql.SQLException:对只转发结果集的无效操作:absolute设置方法为Statement 的设置方法:Statement stmt=con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_O......
  • c++11 std::forward使用场景以及作用
    不使用 std::forward时,下述代码G不管传入什么类型的参数,只会最终调用 voidF(int&a);usingnamespacestd; voidF(int&a){  cout<<"int&version"<<a<<endl;} voidF(int&&a){  //dosomething  cout<<"in......
  • nginx通过四层代理实现端口转发
    nginx通过四层代理实现端口转发公司原有的测试数据库在主机192.168.10.5上边,现在数据库转移到了192.168.10.4上,为了不让各个地方都需要更改地址,现在需要一个四层代理工具,将原来请求到192.168.10.5的3306端口转发到192.168.10.4的3306端口。这个工具,用到了nginx的四层代理。官......
  • nginx 转发
    server{listen80;#listen443ssl;server_name*.*.com;#rewrite^(.*)$https://$host$1permanent;gzipon;gzip_staticon;#需要http_gzip_static_module模块gzip_min_length1k;gzip_comp_level4;gzip_proxiedany......
  • nginx的location匹配顺序是怎么样的?rewrite转发到uptream和直接在proxy_pass转发到ups
    Nginxlocation匹配的顺序在Nginx配置文件中,location指令用于配置请求匹配到的URL路径对应的处理规则。location指令匹配URL路径的方式是先精确匹配,然后正则匹配,最后使用URI重写实现后备匹配。匹配顺序如下:先精确匹配location指令中以=开头的模式;然后正则匹......