c++11新特性——forward和Lambda

简介: c++11新特性——forward和Lambda

一、forward

作用:完美转发,参数在传递过程中,保持原有的属性。即参数原来是左值,则传递之后仍然是左值,若是右值,则传递之后仍然是右值。

在学习forward之前,我们先看一个例子:

int &&a = 5;
// a = 50; // 修改成功
int &&right_ref = a; // 错误

分析:这里a是一个右值引用,指向右值5。 但是,a本身是个左值(如果这里不理解,复习下我之前的文章左值右值)。用右值引用指向左值是不对的。那么,如何保持a自身右值引用的特性呢?forward就是干这个的。

int &&a = 5;
// a = 50; // 修改成功
int &&right_ref = std::forward<int>(a); // ok

下面我们再通过例子来看下:

#include <iostream> 
using namespace std; 
template <class T> 
void Print(T &t) { cout << "L" << t << endl; }
template <class T> 
void Print(T &&t) { cout << "R" << t << endl; }
template <class T> 
void func(T &&t) { 
  Print(t); 
  Print(std::move(t)); 
  Print(std::forward<T>(t)); 
}
int main() { 
  cout << "-- func(1)" << endl; 
  func(1); 
  cout << "-- func(x)" << endl; 
  int x = 10; 
  func(x); // x本身是左值 
  cout << "-- func(std::forward<int>(y))" << endl; 
  int y = 20; 
  func(std::forward<int>(y)); // 
  return 0; 
}

运行结果:

![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/1462219cabb54488ae735871b91ad771.png

二、匿名函数Lambda

2.1 定义

lambda表达式可以看成是一般函数的函数名被略去,返回值使用了一个 -> 的形式表示。唯一与普通函数不同的是增加了“捕获列表”。

2.2 语法格式
int main() { 
  [捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 { 
    // 函数体 
  }
  auto Add = [](int a, int b)->int { return a + b; };
  std::cout << Add(1, 2) << std::endl; //输出3 
  return 0; 
}
2.3 捕获列表

有时候需要在匿名函数体内部使用外部变量,lambda表达式使用捕获列表来传递参数,根据传参的行为,分为:

2.3.1 值捕获

与参数传递类似,值捕获的前提是变量可以拷贝,不同点是,拷贝发生在lambda表达式被创建时,而非调用时。匿名函数体内部不能修改外部变量的值。

void func() { 
  cout << "func" << endl; 
  int c = 12; 
  int d = 30; 
  // 创建时就已经把c、d的值拷贝进去了,所以输出:d = 30;
  auto Add = [c, d](int a, int b)->int { 
    // c = 100; // 编译报错
    cout << "d = " << d << endl; 
    return c; 
  };
  d = 20; 
  std::cout << Add(1, 2) << std::endl; 
}

2.3.2 引用捕获

匿名函数体内部可以修改外部变量。

void func() { 
  cout << "func" << endl; 
  int c = 12; 
  int d = 30; 
  // 创建时就已经把c、d的值拷贝进去了
  auto Add = [&c, &d](int a, int b)->int { 
    c = 100; // 编译ok
    cout << "d = " << d << endl; 
    return c; 
  };
  d = 20; // 因为是引用捕获,且这里修改了d的值,所以输出:20
  std::cout << Add(1, 2) << std::endl; 
}

2.3.3 隐式捕获

手动书写捕获列表,有时候会很复杂。我们可以交给编译器去完成,在捕获列表中写一个 & 或者 = ,向编译器声明是引用捕获还是值捕获。

auto Add = [&](int a, int b)->int { 
    c = 100; // 编译ok
    cout << "d = " << d << endl; 
    return c; 
  };

2.3.4 [] 空捕获列表

表明不能使用外部变量。

auto Add = [](int a, int b)->int { 
    c = 100; // 编译报错
    cout << "d = " << d << endl; 
    return c; // 编译报错
  }; 

2.3.5 表达式捕获

上面4种,值和引用捕获都是捕获的已经在外部作用域声明的变量,因此这些捕获的方式均为左值。c++14之后,支持捕获右值,允许捕获的成员用任意的表达式进行初始化。

// C++14 支持表达式捕获
void func() { 
  cout << "func" << endl; 
  auto important = std::make_unique<int>(1); 
  auto add = [v1 = 1, v2 = std::move(important)](int x, int y) -> int {     
    return x + y + v1 + (*v2); 
  };
  std::cout << add(3,4) << std::endl;
}

2.3.6 泛型Lambda

在c++14之前,Lambda表达式的形参必须执行具体的类型。从c++14开始,支持auto泛型形参。

//泛型 Lambda C++14 
void func() { 
  cout << "func" << endl; 
  auto add = [](auto x, auto y) { return x+y; };
  std::cout << add(1, 2) << std::endl; 
  std::cout << add(1.1, 1.2) << std::endl; 
}

2.3.7 可变Lambda

  • 采用值捕获的方式,lambda不能修改其值,如果想要修改,使用mutable修饰;
  • 采用引用捕获的方式,lambda可以直接修改其值

文章参考与<零声教育>的C/C++linux服务期高级架构


相关文章
|
9天前
|
C语言 C++ 开发者
深入探索C++:特性、代码实践及流程图解析
深入探索C++:特性、代码实践及流程图解析
|
2月前
|
算法 编译器 C++
【C/C++ 泛型编程 应用篇】C++ 如何通过Type traits 判断 Lambda表达式类型?
【C/C++ 泛型编程 应用篇】C++ 如何通过Type traits 判断 Lambda表达式类型?
43 4
|
2月前
|
算法 数据处理 C++
【C++ 20 新特性 算法和迭代器库的扩展和泛化 Ranges】深入浅出C++ Ranges库 (Exploring the C++ Ranges Library)
【C++ 20 新特性 算法和迭代器库的扩展和泛化 Ranges】深入浅出C++ Ranges库 (Exploring the C++ Ranges Library)
106 1
|
5天前
|
存储 程序员 C语言
深入理解C++:从语言特性到实践应用
深入理解C++:从语言特性到实践应用
16 3
|
10天前
|
Java 编译器 Linux
【C++11(二)】lambda表达式以及function包装器
【C++11(二)】lambda表达式以及function包装器
|
24天前
|
编译器 C语言 C++
C++ lambda表达式
C++ lambda表达式
|
24天前
|
算法 编译器 C++
C++中的lambda表达式
C++中的lambda表达式
5 0
|
2月前
|
存储 安全 编译器
【C++】类的六大默认成员函数及其特性(万字详解)
【C++】类的六大默认成员函数及其特性(万字详解)
36 3
|
2月前
|
算法 调度 数据库
【C++20 新特性 Calendar (C++20) − Time zone (C++20)】时间的艺术与科学: C++中的现代日期和时区处理
【C++20 新特性 Calendar (C++20) − Time zone (C++20)】时间的艺术与科学: C++中的现代日期和时区处理
84 3
|
2月前
|
算法 编译器 C++
【C++ 14 新特性 std::integer_sequence 】了解 std::integer_sequence 的使用
【C++ 14 新特性 std::integer_sequence 】了解 std::integer_sequence 的使用
55 1