C++完美转发

2023-05-16

1. std::forawrd

std::forward<T>(arg) 可以实现完美转发,即如果 arg 是一个右值引用,则转发之后结果仍是右值引用;反之,如果 arg 是一个左值引用,则转发之后结果仍是左值引用.

#include <iostream>

struct BigObject
{
	char data[1 << 10];
};

void g(BigObject& o)
{
	std::cout << "lvalue reference\n";
}

void g(BigObject&& o)
{
	std::cout << "rvalue reference\n";
}

template <typename T>
void f(T&& arg)
{
	g(std::forward<T>(arg));
}


int main()
{
	BigObject o;
	f(o);

	f(BigObject());
}
lvalue reference
rvalue reference

2. 为什么需要完美转发

  • 在函数模板编程中,常有一种场景是使用模板参数去调用另一个函数(如,上例中 f 去调用 g),这时候如果只提供值传递版本会显得效率太低。
  • 函数的参数一般会尽可能地设为引用类型,以避免对象拷贝带来的高昂开销.
  • 为了使一个函数既可以接受左值,又可以接受右值,C++11 之前的解决方案是将参数类型设为 const Type&. 但这并不是很方便,如限制了参数是常量.
  • 如果函数 g 既提供了左值引用版本和右值引用版本,则最好的情况是函数 f 可以根据参数类型去调用相应版本的 g. 而完美转发正可以满足此要求.

3. 引用折叠规则

  • 右值引用和右值引用叠加将得到右值引用;
  • 右值引用和左值引用叠加将得到左值引用;
  • 左值引用和左值引用叠加将得到左值引用.
template <typename T>
using TR = T&;
						   // v 的类型
TR<int> v;				 // int&
TR<int>& v;				// int&
TR<int>&& v;			   // int&
template <typename T>
using TRR = T&&;
						    // v 的类型
TRR<int> v;				 // int&&
TRR<int>& v;				// int&
TRR<int>&& v;			   // int&&

4. 完美转发的原理

template< class T >
T&& forward( typename std::remove_reference<T>::type& t ) noexcept;

template< class T >
T&& forward( typename std::remove_reference<T>::type&& t ) noexcept;

std::remove_reference<T> 的作用就是去掉 T 中的引用,它是通过模板特化来实现:

template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&>  {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};

根据上述引用折叠规则,如果 Tint&,则 T&& 即为 int&;反之,如果 Tint&&,则 T&&int&&.

5. forwarding reference

上例函数 f 中的 T&& 实际上被称为 forwarding reference. 它是一种特殊类型的引用,它保留了函数参数的值类别(category),使得可以通过 std::forward 来转发它.

forwarding reference 包括以下两种:

  • 在函数模板中,没有被 constvolatile 修饰的、声明为右值引用的类型形参:

    template<class T>
    int f(T&& x) {                    // x is a forwarding reference
        return g(std::forward<T>(x));
    }
    
    template<class T>
    int g(const T&& x); // x is not a forwarding reference: const T is not cv-unqualified
    
  • auto&&,但如果它跟着一个花括号括起的初始值列表,则它不是 forwarding reference:

    auto&& vec = foo();       // foo() may be lvalue or rvalue, vec is a forwarding reference
    g(std::forward<decltype(vec)>(vec));
    
    auto&& z = {1, 2, 3}; // *not* a forwarding reference (special case for initializer lists)
    
    for (auto&& x: f()) {
    	// x is a forwarding reference; this is the safest way to use range for loops
    }
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++完美转发 的相关文章

随机推荐

  • DJI OSDK开发笔记(N3飞控)(1)——开发工作流程

    DJI OSDK开发笔记 xff08 N3飞控 xff09 xff08 1 xff09 开发工作流程 API层次结构硬件设置一般设置数据串口 连接器引脚排列连接到记载计算机 软件环境设置所有平台下载SDK和所需工具更新固件启用OSDK AP
  • Windows Vista 交互式服务编程

    Windows Vista 对快速用户切换 xff0c 用户账户权限 xff0c 以及服务程序所运行的会话空间都作了很大的改动 xff0c 致使一些原本可以工作的程序不再能够正常工作了 xff0c 我们不得不进行一些改进以跟上 Vista
  • Windows2000 服务器端应用程序开发设计指南-信任成员的管理

    Microsoft的开发者已经完成Microsoft Windows 2000安全性特色的设计工作 xff0c 这些安全性特色比大多数人所习惯的环境更复杂且更有弹性 事实上 xff0c 若加上适当的管理和软件开发 xff0c Windows
  • NoDriveTypeAutoRun键值的作用

    常见的Autorun inf文件格式大致如下 xff1a AutoRun 表示AutoRun部分开始 xff0c 必须输入 icon 61 C ixigua ico 指定给C盘一个个性化的盘符图标C ico open 61 C ixigua
  • Windows系统调用架构分析—也谈KiFastCallEntry函数地址的获取 .

    为什么要写这篇文章 1 因为最近在学习 软件调试 这本书 xff0c 看到书中的某个调试历程中讲了Windows 的系统调用的实现机制 xff0c 其中讲到了从Ring3 跳转到Ring0 之后直接进入了KiFastCallEntry 这个
  • ubuntu rc.local不能正常运行

    查了下rc local有时不能正常运行的原因 xff1a Ubuntu默认将 bin sh链接到 bin dash xff0c 而 etc rc local脚本中用的正是 bin sh xff0c 导致出错 将默认的shell改成bash的
  • 关于建设symbol store的建议

    xfeff xfeff 一 symbol store的需求分析 xff1a 1 我们现在的调试环境严重依赖开发人员自己使用的开发环境 xff0c 缺点在于其他人要进行调试要么搭建一个同样的环境 xff0c 严重地占去大家不必要花费的工作时间
  • 进程防结束之PS_CROSS_THREAD_FLAGS_SYSTEM

    有人投到黑防去了 xff0c 不过黑防不厚道 xff0c 竟然没给完整的代码 xff0c 自己整理一份备用吧 xff0c 驱网 DebugMan 邪八的那群人直接飘过吧 这种方法的关键在于给线程的ETHREAD CrossThreadFla
  • CNN实现入侵检测(kdd99)

    文章目录 1 实验说明2 实验过程2 1 数据预处理2 1 1 导入数据2 1 2 one hot编码2 1 3 归一化2 1 4 标签编码 2 2 数据加载2 3 搭建模型2 4 模型训练 3 实验结果4 完整代码 1 实验说明 CNN模
  • All about VDIs

    This tutorial is an experiment to see if forum users find it useful to have a single collected reference for some common
  • PUTTY无法远程连接服务器故障解决

    对于一个刚刚了解putty工具的新手来说 xff0c 在putty工具使用中有时出现了问题而无法解决 今天就来介绍怎么解决putty无法远程连接服务器的故障 用putty远程连接服务器时 提示错误 server unexpectedlycl
  • 驱动中获取进程名的正确方法

    这是个古老的话题 xff0c 没有技术含量 xff0c 只不过看到网上很多驱动代码在获取进程名时总喜欢去读偏移 EPROCESS ImageFileName xff0c 感觉比较误导新人 这个方法其实很不科学 xff0c 硬编码偏移带来的兼
  • C语言写二进制数据到mysql的Blob字段

    引子 由于调试需要 xff0c 需直接往数据库里写入二进制数据 本来这些数据是由上层软件来写的 xff0c 用的是 C 为了熟悉 C 语言的数据库操作 xff0c 还是决定用 C 来写这段调试代码 概况 xff1a 表名 xff1a Tas
  • 编译器 链接 选项解释:link incrementally的作用

    What is ILT xff08 Incremental Link Table 这两天研究了一下DLL的import export原理 xff0c 看了一些资料 xff0c 无意中发现网上有一篇文章存在错误 xff0c 而这篇文章流传还甚
  • 关于涉密信息系统分级保护的几个问题

    2003年9月7日 xff0c 中共中央办公厅 国务院办公厅转发了 国家信息化领导小组关于加强国家信息安全保障工作的意见 xff0c 其中明确提出了开展信息安全等级保护的任务 xff0c 并指出涉及国家秘密的信息系统 xff08 以下简称涉
  • Launch your application in Vista under the local system account without the UAC popup

    This article describes how to launch an application from session 0 to session 1 under the local system account using a s
  • UTF8ToAnsi 和 AnsiToUTF8

    std string UTF8ToAnsi const std string amp strIn std string amp strOut WCHAR strSrc 61 NULL TCHAR szRes 61 NULL int i 61
  • TCP/IP 配置参数

    TCP IP 配置参数 Windows 2000 TCP IP 协议组件实现从注册表中获取全部配置数据 配置信息 是由安装程序写到注册表中的 一些信息也可以由动态主机配置协议 DHCP 客户 服务提供 xff08 如启用 xff09 本附录
  • ExpLookupHandleTableEntry

    wrk1 2中 ExpLookupHandleTableEntry的内部流程 1 取 Handle EXHANDLE类型 值为tHandle 并将TagBit 低两位 置0 2 取 HandleTable gt NextHandleNeed
  • C++完美转发

    1 std forawrd std forward lt T gt arg 可以实现完美转发 xff0c 即如果 arg 是一个右值引用 xff0c 则转发之后结果仍是右值引用 xff1b 反之 xff0c 如果 arg 是一个左值引用 x