<五>move移动语义和forward类型转发

move : 移动语义,得到右值类型
forward:类型转发,能够识别左值和右值类型

只有两种形式的引用,左值引用和右值引用,万能引用不是一种引用类型,它存在于模板的引用折叠情况,但是能够接受左值和右值
区分左值和右值得一个简单方式就是能不能取地址
一个右值一旦有名字那么就变成了左值

#include <iostream>
using namespace std;

void process(int & i) {
	std::cout << i << " lvalue" << std::endl;
}

void process(int && i) {
	std::cout << i << " r value" << std::endl;
}

template<typename T>
void test(T && v) { //这里的&& 表示万能引用,既能接受左值也能接受右值
	process(v);
}

int main() {

	int i = 100;
	test(i);
	test(200);

	system("pause");
	return 0;
}

<五>move移动语义和forward类型转发

上面的运行结果 我们发现 test(i); 和 test(200); 最后都调用了 void process(int & i) 左值形参,
test(T && v) 接受test(i)的时候,是用左值去接, 接受test(200)的时候,使用右值去接,
其中有一点右值本身是一个左值类型(如何理解?右值本身是有地址有名称的,所以他本身就可以取地址了,他是一个左值)
所以函数形参一定是个左值,他有名字,有空间了,变成了具名对象,200传过去后变成了一个左值.

200 传入 test后就变成了一个左值了,进入了test 函数后没有保留好原始信息,所以 process(v); 就都调用了void process(int & i) 左值形参,
这个我叫做 不完美转发

但是我希望 在test 函数内任然能够保留原始信息,原始的是左值继续保留左值,原始是右值就继续保留右值, 如何实现呢? 完美转发

引用折叠技术

形参 是 T && v ,在模板函数形参,两个引用 在一起会引发引用折叠, 有一个左值引用 最后是=》左值, 两个都是右值 最后是=>右值

即 test(i) + void test(T && v) => T & && i => 左值
即 test(200) + void test(T && v) => T && && 200 => 右值

所以将 函数形参写成 &&

//模板实例化过程中出现这种情况就会发生引用折叠,如果任一尹永伟左值引用,那么结果就是左值引用,
//如果两个都是右值引用,那么结果为右值引用
template<typename T>
void test2(T && v) {	
	std::cout  <<"is int &  " <<  std::is_same_v<T, int &> << std::endl;
	std::cout << "is int    " <<  std::is_same_v<T, int > << std::endl;
}

int main() {

	int i = 100;
	test2(i);
	test2(200);

	system("pause");
	return 0;
}

<五>move移动语义和forward类型转发

template<typename T>
void test2(T && v) {	
	std::cout  <<"is int &  "<< std::is_same_v<T, int &> << std::endl;
	std::cout << "is int    " << std::is_same_v<T, int > << std::endl;
}

int main() {

	int i = 100;
	test2(i);
	test2(200);

	system("pause");
	return 0;
}

test2(i) 调用模板会实例化出如下模板
void test2(int & && v) {	
	std::cout  <<"is int &  "<< std::is_same_v<T, int &> << std::endl;
	std::cout << "is int    " << std::is_same_v<T, int > << std::endl;
}

test2(200) 调用模板会实例化出如下模板
void test2(int && v) {	
	std::cout  <<"is int &  " << std::is_same_v<T, int &> << std::endl;
	std::cout << "is int    " << std::is_same_v<T, int > << std::endl;
}

上面两个实例化出来的模板,形参根据引用折叠技术 
void test2(int & && v) =》void test2(int & v)
void test2(int &&   v) =》void test2(int && v)


即 如果 test2(i)  那么模板中的 T  就是  int &
如果 test2(200 )  那么模板中的 T  就是  int


所以 下面的代码 
template<typename T>
void test(T && v) { //这里的&& 表示万能引用,既能接受左值也能接受右值
	process(v);
}

我们这里这么改一下
template<typename T>
void test(T && v) { //这里的&& 表示万能引用,既能接受左值也能接受右值      
	 
         process(static_cast<T&&>(v));
        // test(i)  => process( static_cast<int & &&>(v)); =>  process( static_cast<int & >(v));
        // test(200)=> process( static_cast<int &&>(v));   =>  process( static_cast<int && >(v));
}


原文链接:https://www.cnblogs.com/erichome/p/16942125.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:<五>move移动语义和forward类型转发 - Python技术站

(0)
上一篇 2023年5月3日
下一篇 2023年5月5日

相关文章

  • 【Visual Leak Detector】源码文件概览

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇对 VLD 源码包中的各文件用途做个概述。同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. 整体概览 2. 文件夹 .teamcity 3 文件夹 lib 3.1 文件夹 cppformat(生成 libformat) 3.2 文件夹 dbghelp 3.3 文件夹 gtest(…

    C++ 2023年4月24日
    00
  • 【Visual Leak Detector】源码下载

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍 VLD 源码的下载。同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. 下载途径 2. 不同下载途径的源文件差异 1. 下载途径 以 v2.5.1 版本为例,可以到 Github-KindDragon-vld 页面下载 master 的 zip 源码包,如下所示: 也可以到 …

    C++ 2023年4月22日
    00
  • 最少步数

    在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100*100)的围棋盘上任选两点A、B,A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一…

    C++ 2023年4月25日
    00
  • C++实现一个线程安全的map

    本文是使用ChatCPT生成的,最终的代码使用起来没问题。代码是通过两轮对话完善的,后面把对话合并后跑不出理想效果就没尝试了。 第一轮对话 请求 c++11实现一个线程安全的map,使用方法与std::map保持一致,实现[]运算符 回复 以下是一个简单的线程安全的map实现,可以使用[]运算符来访问和修改map中的元素: //代码省略,后面一起给出 该实现…

    C++ 2023年5月7日
    00
  • 2023.5.5 面向对象程序设计实验报告

    实验项目名称:模板 一、实验目的 1、熟练掌握函数模板和类模板的定义格式。 2、熟练运用函数模板和类模板解决实际问题。 二、实验内容 1、复数类Complex有两个数据成员:a和b, 分别代表复数的实部和虚部,并有若干构造函数和一个重载-(减号,用于计算两个复数的距离)的成员函数。 要求设计一个函数模板 template < class T > …

    C++ 2023年5月5日
    00
  • C++ 测试框架 GoogleTest 初学者入门篇 乙

    *以下内容为本人的学习笔记,如需要转载,请声明原文链接 微信公众号「ENG八戒」https://mp.weixin.qq.com/s/aFeiOGO-N9O7Ab_8KJ2wxw 开发者虽然主要负责工程里的开发任务,但是每个开发完毕的功能都是需要开发者自测通过的,所以经常会听到开发者提起单元测试的话题。那么今天我就带大伙一起来看看大名鼎鼎的谷歌 C++ 测试…

    C++ 2023年4月18日
    00
  • C++ 并发编程实战 第二章 线程管控

    第二章 线程管控 std::thread 简介 构造和析构函数 /// 默认构造 /// 创建一个线程,什么也不做 thread() noexcept; /// 带参构造 /// 创建一个线程,以 A 为参数执行 F 函数 template <class Fn, class… Args> explicit thread(Fn&&amp…

    C++ 2023年4月17日
    00
  • 前缀和

      一、什么是前缀和 前缀和是一种预处理,用于降低查询时的时间复杂度。 举个例子:给定 n 个整数,然后进行 m 次询问,每次询问求一个区间内值的和。 如果用暴力写法,那每次询问都需要从区间左端点循环到区间右端点求和,时间复杂度较大。 这种时候就可以预先求出该数组的一维前缀和。 则 ans=s[R]-s[L-1] ,其中 L 和 R 是给定的区间。每次询问可…

    C++ 2023年4月17日
    00
合作推广
合作推广
分享本页
返回顶部