服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++11 模板参数的“右值引用”是转发引用吗

C++11 模板参数的“右值引用”是转发引用吗

2021-09-08 12:21jerry_fuyi C/C++

这篇文章主要介绍了C++11 模板参数的“右值引用”是转发引用吗,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在C++11中,&&不再只有逻辑与的含义,还可能是右值引用:

?
1
void f(int&& i);

但也不尽然,&&还可能是转发引用:

?
1
2
template<typename T>
void g(T&& obj);

“转发引用”(forwarding reference)旧称“通用引用”(universal reference),它的“通用”之处在于你可以拿一个左值绑定给转发引用,但不能给右值引用:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
void f(int&& i) { }
 
template<typename T>
void g(T&& obj) { }
 
int main()
{
  int n = 2;
  f(1);
// f(n); // error
  g(1);
  g(n);
}

一个函数的参数要想成为转发引用,必须满足:

  • 参数类型为T&&,没有const或volatile;
  • T必须是该函数的模板参数。

换言之,以下函数的参数都不是转发引用:

?
1
2
3
4
5
6
7
8
9
10
template<typename T>
void f(const T&&);
template<typename T>
void g(typename std::remove_reference<T>&&);
template<typename T>
class A
{
  template<typename U>
  void h(T&&, const U&);
};

另一种情况是auto&&变量也可以成为转发引用:

?
1
auto&& vec = foo();

所以写范围for循环的最好方法是用auto&&:

?
1
2
3
4
5
std::vector<int> vec;
for (auto&& i : vec)
{
  // ...
}

有一个例外,当auto&&右边是初始化列表,如auto&& l = {1, 2, 3};时,该变量为std::initializer_list<int>&&类型。

转发引用,是用来转发的。只有当你的意图是转发参数时,才写转发引用T&&,否则最好把const T&和T&&写成重载(如果需要的话还可以写T&,还有不常用的const T&&;其中T是具体类型而非模板参数)。

转发一个转发引用需要用std::forward,定义在<utility>中:

?
1
 

调用g有几种可能的参数:

  • int i = 1; g(i);,T为int&,调用g(int&);
  • const int j = 2; g(j);,T为const int&,调用g(const int&);
  • int k = 3; g(std::move(k));或g(4);,T为int(不是int&&哦!),调用g(int&&)。

你也许会疑惑,为什么std::move不需要<T>而std::forward需要呢?这得从std::forward的签名说起:

?
1
2
3
4
template<typename T>
constexpr T&& forward(std::remove_reference_t<T>&) noexcept;
template<typename T>
constexpr T&& forward(std::remove_reference_t<T>&&) noexcept;

调用std::forward时,编译器无法根据std::remove_reference_t<T>反推出T,从而实例化函数模板,因此<T>需要手动指明。

但是这并没有从根本上回答问题,或者可以进一步引出新的问题——为什么std::forward的参数不定义成T&&呢?

原因很简单,T&&会把T&、const T&、T&&和const T&&(以及对应的volatile)都吃掉,有了T&&以后,再写T&也没用。

且慢,T&&参数在传入函数是会匹配到T&&吗?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <utility>
 
void foo(int&)
{
  std::cout << "int&" << std::endl;
}
 
void foo(const int&)
{
  std::cout << "const int&" << std::endl;
}
 
void foo(int&&)
{
  std::cout << "int&&" << std::endl;
}
 
void bar(int&& i)
{
  foo(i);
}
 
int main()
{
  int i;
  bar(std::move(i));
}

不会!程序输出int&。在函数bar中,i是一个左值,其类型为int的右值引用。更直接一点,它有名字,所以它是左值。

因此,如果std::forward没有手动指定的模板参数,它将不能区分T&和T&&——那将是“糟糕转发”,而不是“完美转发”了。

最后分析一下std::forward的实现,以下代码来自libstdc++:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
template<typename _Tp>
 constexpr _Tp&&
 forward(typename std::remove_reference<_Tp>::type& __t) noexcept
 { return static_cast<_Tp&&>(__t); }
 
template<typename _Tp>
 constexpr _Tp&&
 forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
 {
  static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
         " substituting _Tp is an lvalue reference type");
  return static_cast<_Tp&&>(__t);
 }
  • 当转发引用T&& obj绑定左值int&时,匹配第一个重载,_Tp即T为int&,返回类型_Tp&&为int&(引用折叠:& &、& &&、&& &都折叠为&,只有&& &&折叠为&&);
  • const int&同理;
  • 当转发引用绑定右值int&&时,匹配第二个重载,_Tp为int,返回类型为int&&;
  • const int&&同理。

综上,std::forward能完美转发。

程序员总是要在Stack Overflow上撞撞墙才能学会一点东西。

到此这篇关于C++11 模板参数的“右值引用”是转发引用吗的文章就介绍到这了,更多相关C++11 右值引用内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/jerry-fuyi/p/12733924.html

延伸 · 阅读

精彩推荐
  • C/C++OpenCV实现拼接图像的简单方法

    OpenCV实现拼接图像的简单方法

    这篇文章主要为大家详细介绍了OpenCV实现拼接图像的简单方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    iteye_183805102021-07-29
  • C/C++关于C语言中E-R图的详解

    关于C语言中E-R图的详解

    今天小编就为大家分享一篇关于关于C语言中E-R图的详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看...

    Struggler095962021-07-12
  • C/C++c/c++内存分配大小实例讲解

    c/c++内存分配大小实例讲解

    在本篇文章里小编给大家整理了一篇关于c/c++内存分配大小实例讲解内容,有需要的朋友们可以跟着学习参考下。...

    jihite5172022-02-22
  • C/C++C语言main函数的三种形式实例详解

    C语言main函数的三种形式实例详解

    这篇文章主要介绍了 C语言main函数的三种形式实例详解的相关资料,需要的朋友可以参考下...

    ieearth6912021-05-16
  • C/C++深入C++拷贝构造函数的总结详解

    深入C++拷贝构造函数的总结详解

    本篇文章是对C++中拷贝构造函数进行了总结与介绍。需要的朋友参考下...

    C++教程网5182020-11-30
  • C/C++c/c++实现获取域名的IP地址

    c/c++实现获取域名的IP地址

    本文给大家汇总介绍了使用c/c++实现获取域名的IP地址的几种方法以及这些方法的核心函数gethostbyname的详细用法,非常的实用,有需要的小伙伴可以参考下...

    C++教程网10262021-03-16
  • C/C++使用C++制作简单的web服务器(续)

    使用C++制作简单的web服务器(续)

    本文承接上文《使用C++制作简单的web服务器》,把web服务器做的功能稍微强大些,主要增加的功能是从文件中读取网页并返回给客户端,而不是把网页代码...

    C++教程网5492021-02-22
  • C/C++C语言实现双人五子棋游戏

    C语言实现双人五子棋游戏

    这篇文章主要为大家详细介绍了C语言实现双人五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    两片空白7312021-11-12