ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

关于C++转发你有这个疑问吗

2022-02-20 22:01:50  阅读:209  来源: 互联网

标签:std move C++ 源码 && 转发 forward 疑问


目录

一、前言

二、疑惑

三、解惑

3.1、知识点回顾(含 std::move 源码分析)

3.2、解惑(std::forward 源码分析)

四、参考文章


一、前言

转发作为C++11的新特性,涉及了右值引用、模板、引用折叠等知识,之前没学好,近来重学了一遍,一是为了自我提升,二是为了准备面试;本文分享一下我对C++转发功能的理解,如有错误望评论留言。

 

二、疑惑

在提出疑问前,先说回顾C++转发的作用:将一个或多个实参连同类型不变地转发给其他函数(《C++ Primer》(中文第5版,612页))。

疑问:如下代码为何能实现C++转发功能,疑惑点在第4行的 std::forward 函数,该函数不是说返回右值引用(即左值)吗,为啥可以传递给函数 g 的第一个形参(右值引用)?(代码来自《C++ Primer》(中文第5版,614页))

template <typename F, typename T1, typename T2>
void flip(F f, T1 &&t1, T2 &&t2)
{
	f(std::forward<T2>(t2), std::forward<T1>(t1));
}

void g(int &&i, int &j)
{
	cout << i << " " << j << endl;
}

int main(int argc, char *argv[])
{
	int i = 9;
	flip(g, i, 42);
	return 0;
}

三、解惑

3.1、知识点回顾(含 std::move 源码分析)

上文“二、疑惑”中的代码涉及如下知识点:

1)右值引用;

2)模板实参推断(引用折叠);

      a)X& &、X& &&、和 X&& & 都折叠成类型 X&;(《C++ Primer》第5版,609页)

      b)类型 X&& && 折叠成 C&&;

3)std::move 工作过程(《C++ Primer》第5版,将此部分放在了“转发”的前面);

std::move 函数源码如下(可在 VS 工具中右键函数名转到定义查看源码):

// TEMPLATE FUNCTION move
template<class _Ty> inline
	constexpr typename remove_reference<_Ty>::type&&
		move(_Ty&& _Arg) _NOEXCEPT
	{	// forward _Arg as movable
    	return (static_cast<typename remove_reference<_Ty>::type&&>(_Arg));
	}

代码中 std::remove_reference<T>::type 作用是脱去引用剩下类型本身,假设 T 为 X&、X&&,则 std::remove_reference<T>::type 为 X;

注意 std::move 的主要作用是将一个左值转换为右值,因此如果某个函数代码和上述相近,则该函数功能和 std::move 一致。

概括为:调用std::move函数得到一个匿名的右值引用,此值可当作右值。

3.2、解惑(std::forward 源码分析)

在此之前请确保先看了上文的“std::move 工作过程”部分;

下面查看 std::forward 的源码,在 VS 工具中右键函数名转到定义查看(有两个模板函数,即模板函数重载,可接受不同参数);

有没发现,和 std::move 的源码几乎如出一辙;

// TEMPLATE FUNCTION forward
template<class _Ty> inline
	constexpr _Ty&& forward(
		typename remove_reference<_Ty>::type& _Arg) _NOEXCEPT
	{	// forward an lvalue as either an lvalue or an rvalue
    	return (static_cast<_Ty&&>(_Arg));
	}

template<class _Ty> inline
	constexpr _Ty&& forward(
		typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
	{	// forward an rvalue as an rvalue
    	static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
    	return (static_cast<_Ty&&>(_Arg));
	}

(PS:为啥突然要分析 std::forward 源码,这是一个偶然发现,之前也反复看了书上的相关章节,无果)

 现在回到 “二、疑惑” 中的代码,我在代码中增加了如下注释,希望对你有帮助。

template <typename F, typename T1, typename T2>
void flip(F f, T1 &&t1, T2 &&t2)
{
	f(std::forward<T2>(t2), //根据模板实参推断(引用折叠),T2为int,  则 std::forward<T2>(t2) 返回 int &&,为匿名右值引用,即右值;
      std::forward<T1>(t1));//根据模板实参推断(引用折叠),T1为int &,则 std::forward<T1>(t1) 返回 int && &,即 int &,为左值;
                            //因此上述实参能够传递给函数 g
}

void g(int &&i, int &j)
{
	cout << i << " " << j << endl;
}

int main(int argc, char *argv[])
{
	int i = 9;
	flip(g, i, 42);
	return 0;
}

四、参考文章

C/C++学习记录:std::forward 源码分析 / 完美转发的作用

C++11尝鲜:右值引用和转发型引用_zwvista的专栏-CSDN博客

如何获取 C++ 标准库的源码 - klchang - 博客园

右值引用 - Microm - 博客园

标签:std,move,C++,源码,&&,转发,forward,疑问
来源: https://blog.csdn.net/lthcth111/article/details/123035767

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有