IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 11 & 14 中的Lambda表达式 -> 正文阅读

[C++知识库]C++ 11 & 14 中的Lambda表达式

auto func = [capture] (params) opt -> ret { func_body; };
[捕获列表] (形参列表) mutable 异常列表-> 返回类型{ 函数体 }
捕获列表:定义lambda函数所在的作用域中的指定变量可以在lambda函数中使用

其中func是可以当作lambda表达式的名字,作为一个函数使用,capture是捕获列表,params是参数表,opt是函数选项(mutable之类), ret是返回值类型,func_body是函数体。
各项的含义:

捕获列表:捕获外部变量,捕获的变量可以在函数体中使用,可以省略,即不捕获外部变量。

形参列表:和普通函数的形参列表一样。可省略,即无参数列表

mutable:mutable 关键字,如果有,则表示在函数体中可以修改捕获变量,根据具体需求决定是否需要省略。

异常列表:noexcept / throw(…),和普通函数的异常列表一样,可省略,即代表可能抛出任何类型的异常。

返回类型:和函数的返回类型一样。可省略,如省略,编译器将自动推导返回类型。

函数体:代码实现。可省略,但是没意义。

lambda表达式允许捕获一定范围内的变量:
[] 不捕获任何变量
[&] 引用捕获,捕获外部作用域所有变量,在函数体内当作引用使用
[=] 值捕获,捕获外部作用域所有变量,在函数内内有个副本使用
[=, &a] 值捕获外部作用域所有变量,按引用捕获a变量
[a] 只值捕获a变量,不捕获其它变量
[this] 捕获当前类中的this指针

C++ 11

#include<iostream>
#include<functional>
using namespace std;

//auto func = [capture] (params) opt -> ret { func_body; };
//            [捕获列表] (形参列表) mutable 异常列表-> 返回类型{ 函数体 }      
//            捕获列表:定义lambda函数所在的作用域中的指定变量可以在lambda函数中使用


/*
其中func是可以当作lambda表达式的名字,作为一个函数使用,capture是捕获列表,params是参数表,opt是函数选项(mutable之类), ret是返回值类型,func_body是函数体。
各项的含义:

捕获列表:捕获外部变量,捕获的变量可以在函数体中使用,可以省略,即不捕获外部变量。

形参列表:和普通函数的形参列表一样。可省略,即无参数列表

mutable:mutable 关键字,如果有,则表示在函数体中可以修改捕获变量,根据具体需求决定是否需要省略。

异常列表:noexcept / throw(...),和普通函数的异常列表一样,可省略,即代表可能抛出任何类型的异常。

返回类型:和函数的返回类型一样。可省略,如省略,编译器将自动推导返回类型。

函数体:代码实现。可省略,但是没意义。

lambda表达式允许捕获一定范围内的变量:
[]          不捕获任何变量
[&]         引用捕获,捕获外部作用域所有变量,在函数体内当作引用使用
[=]         值捕获,捕获外部作用域所有变量,在函数内内有个副本使用
[=, &a]     值捕获外部作用域所有变量,按引用捕获a变量
[a]         只值捕获a变量,不捕获其它变量
[this]      捕获当前类中的this指针


*/
int main()
{
//lambda in C++ 11
//g++ lambda.cpp -Wall -std=c++11 -o test && ./test

//step 1 打印输出
    auto basiclambda01=[](){cout<<"hello lambda"<<endl;} ;//注:参数列表为空时可以省略“ ( )”   ,如果函数内容是单个返回语句(只有一条返回语句),那么“ -> 返回类型”也可以省略
    basiclambda01();
    //cout<<[](){cout<<"hello lambda"<<endl;}<<"\n";
//step 2 返回值
    auto basiclambda02=[](int a, int b)->int{
        cout<<"param and ret lambda"<<endl;
        return a+b;
    };
    int result = basiclambda02(3,4);
    cout<<result<<endl;
    cout<<basiclambda02(4,5)<<endl;

//step 3  使用捕获列表, 引用捕获, 可以修改data
    int data = 2;
    auto basicLambda03 =  [&data](){
    cout<<"inside basicLambda03 = " <<++data<<endl;
    };
    basicLambda03();
    cout<<"outside basicLambda03 = " << data<<endl;// same to inside basicLambda03
//step 4  值捕获
    /*
    使用传引用的方式能够在lambda函数体内部修改传入的捕捉变量。但是如果是以传值的方式进行捕捉,即便捕捉变量为非const,在lambda函数内部也不能够修改变量的值,
    因为传入的是捕捉变量的副本,如果想要修改,那么需要在函数定义时加上关键字mutable,此时即便传入参数为空," () "也不可省略  
    */
    auto basicLambda04 =  [data]()mutable {
    cout<<"inside basicLambda04 = " <<++data<<endl;
    };
    basicLambda04();
    cout<<"outside basicLambda04 = " << data<<endl;// not same to inside basicLambda03
//step 5  隐式捕获
// 手动书写捕获列表有时候是非常复杂的,这种机械性的工作可以交给编译器来处理,这时候可以在捕获列表中写一个 
// & 或 = 向编译器声明采用引用捕获或者值捕获.

    //隐式引用捕获
    auto basicLambda05 =  [&](){
    cout<<"inside basicLambda05 = " <<++data<<endl;
    };
    basicLambda05();
    cout<<"outside basicLambda05 = " << data<<endl;// same to inside basicLambda05

    //隐式值捕获
    auto basicLambda06 =  [=]()mutable{
    cout<<"inside basicLambda06 = " <<++data<<endl;
    };
    basicLambda06();
    cout<<"outside basicLambda06 = " << data<<endl;// same to inside basicLambda06

    // 总结一下,捕获提供了lambda 表达式对外部值进行使用的功能,捕获列表的最常用的四种形式可以是:
    // [] 空捕获列表
    // [name1, name2, ...] 捕获一系列变量
    // [&] 引用捕获, 让编译器自行推导捕获列表
    // [=] 值捕获, 让编译器执行推导引用列表


    return 0;
}

C++ 14

#include <iostream>
#include <memory>//for make_unique
#include <utility>

int main() {
    //lambda in C++ 14
    //g++ lambda.cpp -Wall -std=c++11 -o test && ./test

//step 1 表达式捕获
/*
之前提到的值捕获、引用捕获都是已经在外层作用域声明的变量,因此这些捕获方式捕获的均为左值,而不能捕获右值。
C++14 给与了我们方便,允许捕获的成员用任意的表达式进行初始化,这就允许了右值的捕获,
被声明的捕获变量类型会根据表达式进行判断,判断方式与使用 auto本质上是相同的:

*/
    auto important = std::make_unique<int>(1);
    auto add01 = [v1 = 1, v2 = std::move(important)](int x, int y) -> int {
        return x+y+v1+(*v2);
    };
    std::cout << add01(3,4) << std::endl;
/*
在上面的代码中,important是一个独占指针,是不能够被捕获到的,这时候我们需要将其转移为右值,在表达式中初始化。
*/

//step 3 泛型 Lambda
    auto add02 = [](auto x, auto y) {
    return x+y;
    };
    std::cout <<add02(1, 2)<< std::endl;
    std::cout <<add02(1.1, 2.2)<< std::endl;

    return 0;
}

c++11 中 auto 关键字不能够用在参数表里,这是因为这样的写法会与模板的功能产生冲突。
但是 Lambda 表达式并不是普通函数,所以 Lambda 表达式并不能够模板化。
这就为我们造成了一定程度上的麻烦:参数表不能够泛化,必须明确参数表类型。

幸运的是,这种麻烦只存在于 C++11 中,从 C++14 开始,
Lambda 函数的形式参数可以使用 auto 关键字来产生意义上的泛型:

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-29 14:46:37  更:2021-07-29 14:46:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/28 3:01:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码