一文搞懂C++11万能引用和右值引用

 更新时间:2022年03月25日 10:43:03   作者:luoyayun361  
本文主要介绍了C++11万能引用和右值引用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

前言

我们通过一个问题来进入今天的话题:
1.形如 “type&&” 的结构,就是右值引用吗?
2.以下哪些属于右值引用?

① void fun(Widget && param);
② Widget && var1= Widget();
③ auto && var2 = var1;
④ template<typename T> void f(std::vector<T>&& param);
⑤ template<typename T> void f(T&& param);

带着以上的问题,我们来看一下到底type&&的结构包含了哪些含义。

正文

实际上,type&& 有两种不同的含义。
其中一种就是 右值引用。它仅仅会绑定右值,用于识别出可移对象。
另外一种含义,则表示既可以是右值引用,也可以是左值引用。这种双重特性使其可以绑定到右值,也可以绑定到左值。还可以绑定到const对象或非const对象,以及volatile对象,甚至可以绑定那些既带有const又带有volatile的对象,拥有很强的灵活性,这就是万能引用。

那么,既然以上两种含义都是 type&& 结构,那么如何来区分二者呢?

万能引用

万能引用通常会在两种场景现身:函数模板的形参 和 auto声明。
示例如下:

template<typename T> 
void f(T&& param);   //param是个万能引用
 auto && var2 = var1;

以上两种场景的共同之处,在于它们都涉及型别推导。

在模板f中,param的类型是推导得到的,而在var2的声明语句中,var2的类型也是推导得到的。

因为万能引用首先是个引用,所以初始化是必须的。万能引用的初始化物会决定它代表的是个左值还是右值引用,如果初始化物是左值,万能引用就会对应得到一个左值引用,同理,如果初始化物是右值,万能引用就会对应得到一个右值引用。
对于作为函数形参的万能引用而言,初始化物在调用处提供:

template<typename T> 
void f(T&& param);

Widget w;
f(w);             //左值被传递给f,param的类型是Widget&,即左值引用

f(std::move(w));  //右值被传递给f,param的类型是Widget&&,即右值引用

有一个需要注意的问题是,万能引用除了要涉及型别推导,还有一个条件必须限定,就是必须要是“T&&”结构才行。
而类似

template<typename T> 
void f(std::vector<T>&& param);   //param是右值引用

这样的类型并不是万能引用,仅仅只是一个右值引用。

而且,如果有const修饰也不可能成为万能引用,比如:

template<typename T> 
void f(const T&& param);  //param是右值引用

那么,位于模板内是不是就一定就会涉及到型别推导呢? 还真不能保证。看以下示例:

template <class T,class Allocator = allocator<T>>
class vector{
public:
    void push_back(T&& x);
    ...
};

以上是来自C++标准中vector类

这里的push_back的形参具备万能引用的正确形式,但是在本示例中,并不涉及到类型推导。因为push_back作为vector本身的一部分,如果不存在特定的vector实例,则它也无从存在。该实例的具体类型完全决定了push_back的声明类型。
如:

std::vector<Widget> v;

会导致std::vector模板具现化为如下实例:

template <class Widget,class Allocator = allocator<Widget>>
class vector{
public:
    void push_back(Widget&& x);  //右值引用
    ...
};

现在就能看清楚push_back并未涉及到类型推导。

而vector中的另外一个函数却涉及到了类型推导,如下:

template <class T,class Allocator = allocator<T>>
class vector{
public:
    template<class... Args>
    void emplace_back(Args&&... args);
    ...
};

以上emplace_back函数的形参 Args独立于vector的型别形参T,所以Args必须在每次emplace_back被调用时进行推导。所以这里的args是个万能引用。

最后,我们前面也提到过,auto变量也可以作为万能引用。确切的说,声明为auto&&的变量都是万能引用,因为肯定涉及到型别推导并且肯定有正确的形式(“T&&”)

比如在C++14中 lambda表达式可以声明auto&&形参。

结语

通过以上描述,终于搞清楚了万能引用和右值引用的区别,那么回到文中最前面的问题,③⑤都是万能引用,其他三个为右值引用,这下不会搞错了。

总结如下:

  • 如果函数模板形参具备T&&型别,并且T的型别是推导而来,或如果对象使用auto&&声明其类型,则该形参或对象就是万能引用
  • 如果型别声明不精确地具备type&&的形式,或者型别推导并未发生,则type&&就代表右值引用
  • 若采用右值来初始化万能引用,就会得到一个右值引用,如果采用左值来初始化,则会得到一个左值引用。

参考:

Effective Modern C++

到此这篇关于一文搞懂C++11万能引用和右值引用的文章就介绍到这了,更多相关C++11万能引用和右值引用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于C语言中的指针与二维数组

    关于C语言中的指针与二维数组

    这篇文章主要介绍了关于C语言中的指针与二维数组,C语言中,指针是一个复杂但又灵活多变的知识点,我们知道,在一维数组中,对于一个数组a[],*a,a,&a,都表示a的首地址,但如果与二维数组混合使用,就显得更为复杂了,需要的朋友可以参考下
    2023-07-07
  • 浅谈C++中的构造函数分类及调用规则

    浅谈C++中的构造函数分类及调用规则

    这篇文章主要介绍了C++中的构造函数分类及调用规则,文中根据参数写出了几种不同类型的构造函数并解释了如何调用,需要的朋友可以参考下
    2016-03-03
  • 简要说明C语言中指针函数与函数指针的区别

    简要说明C语言中指针函数与函数指针的区别

    这篇文章主要介绍了C语言中指针函数与函数指针的区别,指针函数和函数指针是C语言入门学习中的基础知识,需要的朋友可以参考下
    2016-04-04
  • C语言中strcpy()函数的具体实现及注意事项

    C语言中strcpy()函数的具体实现及注意事项

    C语言库函数char *strcpy(char *dest, const char *src)把src所指向的字符串复制到dest,下面这篇文章主要给大家介绍了关于C语言中strcpy()函数的具体实现及注意事项的相关资料,需要的朋友可以参考下
    2022-11-11
  • C++动态规划之背包问题解决方法

    C++动态规划之背包问题解决方法

    这篇文章主要介绍了C++动态规划之背包问题解决方法,实例分析了背包问题的原理与C++实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-04-04
  • VisualStudio 使用Visual Leak Detector检查内存泄漏

    VisualStudio 使用Visual Leak Detector检查内存泄漏

    这篇文章主要介绍了VisualStudio 使用Visual Leak Detector检查内存泄漏的相关资料,需要的朋友可以参考下
    2015-07-07
  • C++ STL中vector容器的使用

    C++ STL中vector容器的使用

    这篇文章主要为大家详细介绍了C++ vector容器的使用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • VC++的if语句应用范围分析

    VC++的if语句应用范围分析

    这篇文章主要介绍了VC++的if语句应用范围分析,对VC++初学者有很好的参考学习价值,需要的朋友可以参考下
    2014-08-08
  • C++使用WideCharToMultiByte函数生成UTF-8编码文件的方法

    C++使用WideCharToMultiByte函数生成UTF-8编码文件的方法

    用来映射Unicode字符串的WideCharToMultiByte函数经常被用来进行UTF-8编码的转换,以下我们将看到C++使用WideCharToMultiByte函数生成UTF-8编码文件的方法,首先先来对WideCharToMultiByte作一个详细的了解:
    2016-06-06
  • C++数组放在main函数内外的区别

    C++数组放在main函数内外的区别

    大家好,本篇文章主要讲的是C++数组放在main函数内外的区别,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01

最新评论