热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C++超详细梳理lambda和function的使用方法

C++在C11标准中引入了匿名函数,即没有名字的临时函数,又称之为lambda表达式.lambda表达式 实质上是创建一个匿名函数对象,这篇文章主要介绍了lambda和function的使用方法

lambda表达式

lambda表达式又称为匿名表达式,是C11提出的新语法。[]存储lambda表达式要捕获的值,()内的参数为形参,可供外部调用传值。lambda表达式可以直接调用

 // 1  匿名调用
    [](string name)
    {
        cout <<"this is anonymous" <

上述代码定义了一个匿名函数后直接调用。我们可以通过auto初始化一个变量存储lambda表达式

 // 2 通过auto赋值
    auto fname = [](string name)
    {
        cout <<"this is auto  " <

通过auto定义fname,然后存储了lambda表达式,之后调用fname即可。也可以通过函数指针的方式接受lambda表达式

    typedef void (*P_NameFunc)(string name);
    // 3 函数指针
    P_NameFunc fname2 = [](string name)
    {
        cout <<"this is P_NameFunc " <

P_NameFunc定义了fname2函数指针接受了lambda表达式。也可以通过function对象接受lambda表达式,function类是C11新增的语法。

// 4 function
    function funcName;
    funcName = [](string name)
    {
        cout <<"this is function " <

用一个function对象接受了lambda表达式,同样可以调用该function对象funcName达到调用lambda的效果。

谈谈lambda的捕获

1 值捕获

    int age = 33;
    string name = "zack";
    int score = 100;
    string job = "softengineer";
    //值捕获
    [age, name](string name_)
    {
        cout <<"age is " <

上述lambda表达式捕获了age和name,是以值的方式来捕获的。所以无法在lambda表达式内部修改age和name的值,如果修改age和name,编译器会报错,提示无法修改const常量,因为age和name是以值的方式被捕获的。

2 引用捕获

    int age = 33;
    string name = "zack";
    int score = 100;
    string job = "softengineer";
    [&age, &name](string name_)
    {
        cout <<"age is " <

[]里age和name前边添加了&,此时age和name是以引用方式捕获的。所以可以在lambda表达式中修改age和name的值。

C++的lambda表达式虽然可以捕获局部变量的引用,达到类似闭包的效果,但不是真的闭包,golang和python等语言通过闭包捕获局部变量后可以增加局部变量的声明周期,C++无法做到这一点,所以下面的调用会出现崩溃。

vector> vec_Funcs;
void use_lambda2()
{
    int age = 33;
    string name = "zack";
    int score = 100;
    string job = "softengineer";
    vec_Funcs.push_back([age, name](string name_)
                        {   cout <<"this is value catch " <

use_lambda2中将lambda表达式存储在function类型的vector里,当use_lambda2结束后,里边的局部变量都被释放了,而vector中的lambda表达式还存储着局部变量的引用,在调用use_lambda3时调用lambda表达式,此时访问局部变量已经被释放了,所以导致程序崩溃。

3 全部用值捕获,name用引用捕获

    int age = 33;
    string name = "zack";
    int score = 100;
    string job = "softengineer";
    [=, &name]()
    {
        cout <<"age is " <

通过=表示所有变量都以值的方式捕获,如果希望某个变量以引用方式捕获则单独在这个变量前加&。

4 全部用引用捕获,只有name用值捕获

   int age = 33;
   string name = "zack";
   int score = 100;
   string job = "softengineer";
   [&, name]()
   {
        cout <<"age is " <

通过&方式表示所有变量都已引用方式捕获,如果希望某个变量以值方式捕获则单独在这个变量前加=。

万能的function

我们可以用function存储形参和返回值相同的一类函数指针,可调用对象,lambda表达式等。

void use_function()
{
    list> list_Funcs;
    //存储函数对象
    list_Funcs.push_back(FuncObj());
    //存储lambda表达式
    list_Funcs.push_back([](string str)
                         { cout <<"this is lambda call " <

bind操作

C11同样提供了bind操作,将原函数的几个参数通过bind绑定传值,返回一个新的可调用对象。

    //绑定全局函数
    auto newfun1 = bind(globalFun2, placeholders::_1, placeholders::_2, 98, "worker");
    //相当于调用globalFun2("Lily",22, 98,"worker");
    newfun1("Lily", 22);
    //多传参数没有用,相当于调用globalFun2("Lucy",28, 98,"worker");
    newfun1("Lucy", 28, 100, "doctor");
    auto newfun2 = bind(globalFun2, "zack", placeholders::_1, 100, placeholders::_2);
    //相当于调用globalFun2("zack",33,100,"engineer");
    newfun2(33, "engineer");
    auto newfun3 = bind(globalFun2, "zack", placeholders::_2, 100, placeholders::_1);
    newfun3("coder", 33);

placeholders表示占位符,_1表示新生成函数的第一个参数, _2表示新生成函数的第二个参数,将这些参数传递给原函数达到占位的效果,原函数的其余参数通过bind绑定固定值。

接下来定义类

class BindTestClass
{
public:
    BindTestClass(int num_, string name_) : num(num_), name(name_) {}
    static void StaticFun(const string &str, int age);
    void MemberFun(const string &job, int score);
public:
    int num;
    string name;
};

实现静态函数和成员函数

void BindTestClass::StaticFun(const string &str, int age)
{
    cout <<"this is static function" <

我们通过bind绑定静态成员函数

    //绑定类的静态成员函数,加不加&都可以
    // auto staticbind = bind(BindTestClass::StaticFun, placeholders::_1, 33);
    auto staticbind = bind(&BindTestClass::StaticFun, placeholders::_1, 33);
    staticbind("zack");

新生成的staticbind函数可以直接传递一个参数zack就完成了调用。接下来用bind绑定成员函数

    BindTestClass bindTestClass(33, "zack");
    // 绑定类的成员函数,一定要传递对象给bind的第二个参数,可以是类对象,也可以是类对象的指针
    // 如果要修改类成员,必须传递类对象的指针
    auto memberbind = bind(BindTestClass::MemberFun, &bindTestClass, placeholders::_1, placeholders::_2);
    memberbind("coder", 100);
    auto memberbind2 = bind(BindTestClass::MemberFun, placeholders::_3, placeholders::_1, placeholders::_2);
    memberbind2("coder", 100, &bindTestClass);
    //绑定类成员时,对象必须取地址
    auto numbind = bind(&BindTestClass::num, placeholders::_1);
    std::cout <

当然也可以直接用function对象接受bind返回的结果

    // function接受bind返回的函数
    function funcbind = bind(globalFun2, "zack", placeholders::_1, 100, placeholders::_2);
    funcbind(33, "engineer");
    // function接受bind 成员函数
    function funcbind2 = bind(BindTestClass::MemberFun, &bindTestClass, placeholders::_1, placeholders::_2);
    funcbind2("docker", 100);
    function funcbind3 = bind(BindTestClass::MemberFun, placeholders::_3, placeholders::_1, placeholders::_2);
    funcbind3("driver", 100, &bindTestClass);
    // function 直接接受成员函数,function的模板列表里第一个参数是类对象引用
    function functomem = BindTestClass::MemberFun;
    functomem(bindTestClass, "functomem", 88);
    // function 绑定类的静态成员函数
    function funbindstatic = bind(&BindTestClass::StaticFun, placeholders::_1, 33);
    funbindstatic("Rolis");

lambda和bind的使用就介绍到这里

源码链接

视频链接

到此这篇关于C++超详细梳理lambda和function的使用方法的文章就介绍到这了,更多相关C++ lambda和function内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
author-avatar
mobiledu2502939473
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有