在C++模板编程中,完美转发(Perfect Forwarding)是一种技术,旨在保留函数参数的值类别,即在将参数传递到另一个函数时,无论参数是左值还是右值,都能够保持它的原始性质,而不会因为转发丢失性能或引入不必要的拷贝。

完美转发的关键在于通过模板的转发引用(Forwarding Reference),结合 std::forward,将参数以最合适的形式传递给目标函数。

为什么需要完美转发?

在某些情况下,我们希望编写一个通用的函数模板,这个函数模板接收一个可调用对象,并将参数传递给这个可调用对象。

为了避免不必要的拷贝(尤其是右值被拷贝的情况),我们需要一种机制来将参数的值类别保持下来,这就是完美转发的目的。

什么是转发引用?

当一个模板参数被定义为 T&& 时,它并不总是表示右值引用。在模板的上下文中,T&& 是一个特殊的类型,称为转发引用(有时也叫万能引用)。它具有这样的行为:

  • 如果传入的是左值T&& 被推导为 T&(左值引用)。
  • 如果传入的是右值T&& 被推导为 T&&(右值引用)。

这使得我们能够编写一个函数模板,既能接受左值参数,又能接受右值参数。

完美转发的核心:std::forward

完美转发的核心技术是通过 std::forward 来实现的。std::forward 是一个标准库函数,它的作用是在模板中根据参数的类型完美地转发参数:

  • 如果参数是左值,std::forward 会保持它为左值。
  • 如果参数是右值,std::forward 会将其转发为右值。

完美转发的使用示例

以下是一个使用完美转发的简单示例:

#include <iostream>
#include <utility> // for std::forward // 一个通用的函数模板,用于接收任意的可调用对象和参数,并调用它
template <typename F, typename... Args>
void wrapper(F&& f, Args&&... args) {
// 使用std::forward来完美转发参数
std::forward<F>(f)(std::forward<Args>(args)...);
} // 左值引用和右值引用的两个重载函数
void foo(int& x) {
std::cout << "Lvalue reference called: " << x << std::endl;
} void foo(int&& x) {
std::cout << "Rvalue reference called: " << x << std::endl;
} int main() {
int a = 10; // 调用 wrapper,传递左值
wrapper(foo, a); // 输出: Lvalue reference called: 10 // 调用 wrapper,传递右值
wrapper(foo, 20); // 输出: Rvalue reference called: 20 return 0;
}

在这个例子中,wrapper 函数模板通过 std::forward 来实现完美转发:

  • wrapper(foo, a) 被调用时,a 是一个左值,因此 foo(int& x) 被调用。
  • wrapper(foo, 20) 被调用时,20 是一个右值,因此 foo(int&& x) 被调用。

通过 std::forward,我们能够在传递参数的过程中避免不必要的拷贝和移动,保持参数的原始值类别。

总结

完美转发是在模板编程中通过转发引用T&&)和 std::forward 来保证参数的值类别(左值或右值)不变的一种技术。

它的目的是在模板函数中高效传递参数,避免不必要的拷贝或移动,进而提高程序性能。

完美转发(模板)--T&&的更多相关文章

  1. C++11新特性 变参模板、完美转发(简述)

    变参模板 (Variadic Template) - 使得 emplace 可以接受任意参数,这样就可以适用于任意对象的构建 完美转发 - 使得接收下来的参数 能够原样的传递给对象的构造函数,这带来另 ...

  2. [C++中级进阶]001_C++0x里的完美转发到底是神马?

    [C++中级进阶]001_C++0x里的完美转发到底是神马? 转载至:http://www.cnblogs.com/alephsoul-alephsoul/archive/2013/01/10/285 ...

  3. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part8:Perfect Forwarding(完美转发):解决方案

    本文为第八部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.ht ...

  4. 第16课 右值引用(3)_std::forward与完美转发

    1. std::forward原型 template <typename T> T&& forward(typename std::remove_reference< ...

  5. (原创)C++11改进我们的程序之move和完美转发

    本次要讲的是右值引用相关的几个函数:std::move, std::forward和成员的emplace_back,通过这些函数我们可以避免不必要的拷贝,提高程序性能.move是将对象的状态或者所有权 ...

  6. c++11 标准库函数 std::move 和 完美转发 std::forward

    c++11 标准库函数 std::move 和 完美转发 std::forward #define _CRT_SECURE_NO_WARNINGS #include <iostream> ...

  7. 完美转发(perfect forwarding)、universal reference、引用折叠(collasping)

    首先要分清: C++里的值只有两种值:左值.右值.—— 其本质应该是内存中存储的值/instance分两种:一种是持久的,一种是“短暂的” 也只有两种引用: 左值引用.右值引用. ——引用,就是这个内 ...

  8. [c++11]右值引用、移动语义和完美转发

    c++中引入了右值引用和移动语义,可以避免无谓的复制,提高程序性能.有点难理解,于是花时间整理一下自己的理解. 左值.右值 C++中所有的值都必然属于左值.右值二者之一.左值是指表达式结束后依然存在的 ...

  9. [转][c++11]我理解的右值引用、移动语义和完美转发

    c++中引入了右值引用和移动语义,可以避免无谓的复制,提高程序性能.有点难理解,于是花时间整理一下自己的理解. 左值.右值 C++中所有的值都必然属于左值.右值二者之一.左值是指表达式结束后依然存在的 ...

  10. Effective Modern C++:05右值引用、移动语义和完美转发

    移动语义使得编译器得以使用成本较低的移动操作,来代替成本较高的复制操作:完美转发使得人们可以撰写接收任意实参的函数模板,并将其转发到目标函数,目标函数会接收到与转发函数所接收到的完全相同的实参.右值引 ...

随机推荐

  1. JavaScript中的new map()和new set()使用详细(new map()和new set()的区别)

    简介:new Map(): 在JavaScript中,new Map()用于创建一个新的 Map 对象.Map 对象是一种键值对的集合,其中的键是唯一的,值可以重复.new Set(): 在JavaS ...

  2. Python异常处理try+except用法

    1.except是用来捕获程序异常的 异常代码如: ModuleNotFoundError(没有找到模块,安装提示的模块即可) AttributeError(没有访问属性) TypeError(类型错 ...

  3. 3、SpringMVC之RequestMapping注解

    3.1.环境搭建 创建名为spring_mvc_demo的新module,过程参考2.1节 3.1.1.创建SpringMVC的配置文件 <?xml version="1.0" ...

  4. 【Vue】Re04 指令:第二部分

    一.v-on指令 作用是用来将元素绑定事件监听器,触发特定的函数执行一定功能 关键字:事件监听 <!DOCTYPE html> <html lang="en"&g ...

  5. 【Vue】Re01 理论概念和入门上手

    一.Vue概述 什么是渐进式?1.把Vue作应用的一部分嵌套项目中2.如果完全抛弃其他组件和框架,Vue又具有丰富的生态和库莱支持3.Core + Router + VueX 满足项目绝大多数的需求- ...

  6. 并行化强化学习 —— 初探 —— 并行reinforce算法的尝试 (中篇:强化学习在大规模仿真环境下单步交互并行化设计的可行性)

    本篇博客是前篇博客并行化强化学习 -- 初探 -- 并行reinforce算法的尝试 (上篇:强化学习在多仿真环境下单步交互并行化设计的可行性)的继续,文中代码地址为:https://gitee.co ...

  7. 【转载】 windows python3 安装 openai gym 的 atari_py

    版权声明:本文为CSDN博主「dai1056318647」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/dai ...

  8. Ubuntu系统:NVIDIA显卡关闭图形显示 —— 彻底禁用NVIDIA GPU 的显示输出接口 —— ubuntu无桌面方式启动 —— NVIDIA显卡模式切换(显示模式切换为计算模式)

    相关: ubuntu desktop改用无桌面方式启动 在使用Linux做异构计算等科学计算的时候一个常见的问题就是: NVIDIA显卡关闭图形显示 -- 彻底禁用NVIDIA GPU 的显示输出接口 ...

  9. 《最新出炉》系列初窥篇-Python+Playwright自动化测试-64 - Canvas和SVG元素推拽

    1.简介 今天宏哥分享的在实际测试工作中很少遇到,比较生僻,如果突然遇到我们可能会脑大.懵逼,一时之间不知道怎么办?所以宏哥这里提供一种思路供大家学习和参考. 2.SVG简介 svg也是html5新增 ...

  10. 讲师招募 | Apache SeaTunnel Meetup等你来秀!

    2024年第三季度已经悄然开启,猛回头才发现今年的时日竟然已经过半!这半年又是在忙忙碌碌中度过,好在看着社区发展年中汇总的一串串数字,似乎都在预示着社区将在一条正确的轨道上,朝着好的方向继续发展.但又 ...