C++ 学习系列 1 -- 左值、右值与万能引用

1. 何为左值?何为右值?

简单的说,左值可以放在等号的左边,右值可以放在等号的右边。

左值可以取地址,右值不能取地址。

1.1 左值举例:

  • 变量、函数或数据成员
  • 返回左值引用的表达式 如 ++x、x = 1、cout << ' '  int x = 0

1.2 右值举例:

  • 返回非引用类型的表达式
    如 x++、x + 1
  • 除字符串字面量之外的字面量如 42、true
将亡值(xvalue)
  • 隐式或显式调用函数的结果,该函数的返回类型是对所返回对象类型的右值引用
#include
#include
using namespace std;
void print(string& str)
{
    cout << "left val: " <

输出:

C++ 学习系列 1 -- 左值、右值与万能引用_第1张图片

 1.3 左值引用与右值引用

 

规则简化如下:

左值引用   {左值}  
右值引用   {右值}
常左值引用  {右值}
string f()
{
   return "bbb";
}

int main() 
{

  string &s1 = "asd";  // error
  const string &s2 = "asd";  // ok
  const string& s3 = f();  // ok
  
  string&& a2 = "defg"; // ok
  string&& a3 = f(); // ok
  
  return 0;
}

  1.4 引入右值引用意义

  可以延长右值的生命周期,右值的生命周期可以与右值引用变量相同

2. 完美转发

2.1  转发引用

在 T 是模板参数时,T&& 的作用主要是保持值类别进行转发,它有个名字就叫“转发引用”(forwarding reference)。因为既可以是左值引用,也可以是右值引用,它也曾经被叫做“万能引用”(universal reference)。

#include
#include
using namespace std;
void print(const string& str)
{
    cout << "left val: " <
void f(T&& param)
{
    print(forward(param));
}

int main(int argc, char *argv[])
{
    string str1 = "hello 1";
    const string& bb = "abc";
    const string& bb2 = ff();


    f(str1); // left value
    f(bb); // left value
    f(bb2); // left value
    f("abcd"); // rightvalue
    f(ff()); // right value

    return 0;
}

输出:

C++ 学习系列 1 -- 左值、右值与万能引用_第2张图片

 2.2  完美转发 std::forward

 2.1.1 源码解析
  • 转发左值
template
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
{ return static_cast<_Tp&&>(__t); }

先通过 remove_reference 获得类型type,定义_t为左值引用的左值变量,通过 static_cast 进行强制转换

  • 转发右值
template
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为右值引用的左值变量,除此之外中间加了一个断言,表示当不是左值的时候,也就是右值,才进行static_cast转换。
2.1.2  remove_reference 解析
template
struct remove_reference
{ typedef _Tp   type; };

// 特化版本
template
struct remove_reference<_Tp&>
{ typedef _Tp   type; };

template
struct remove_reference<_Tp&&>
{ typedef _Tp   type; };

remove_reference的作用是去除T中的引用部分,只获取其中的类型部分。无论T是左值还是右值,最后只获取它的类型部分。

现代C++之万能引用、完美转发、引用折叠 - 知乎 (zhihu.com)

你可能感兴趣的:(学习)