C++系列十:日常学习-Lambda表达式

这篇具有很好参考价值的文章主要介绍了C++系列十:日常学习-Lambda表达式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录
  • 前言
  • 必备理论知识:
  • 例子:
  • 20230920 加
    • 例如
    • 对函数指针和指针函数补充:

前言

有C#经验,使用起来,驾轻就熟。
就是语法糖。但是也要熟悉用法,才好众享丝滑。

内容参考:
Chatjpt、文心一言

必备理论知识:

捕获列表:
[]:默认不捕获任何变量;
[=]:默认以值捕获所有变量;内部有一个相应的副本
[&]:默认以引用捕获所有变量;
[x]:仅以值捕获x,其它变量不捕获;
[&x]:仅以引用捕获x,其它变量不捕获;
[=, &x]:默认以值捕获所有变量,但是x是例外,通过引用捕获;
[&, x]:默认以引用捕获所有变量,但是x是例外,通过值捕获;
[this]:通过引用捕获当前对象(其实是复制指针);
[*this]:通过传值方式捕获当前对象;

lambda表达式的参数形式:
1. 无参数:[]() { /* function body */ };
2. 具名参数:[](int a, int b) { /* function body */ };
3. 默认参数:[](int a = 0, int b = 1) { /* function body */ };
4. 参数包:[](int a, ...) { /* function body */ };

注意点:
1. 有箭头就必要有显式返回类型 -> int
2. lambda 表达式在某些情况下可能会比函数指针或函数对象更耗费资源,需要注意性能问题。
3. 慎重选择捕获列表中的变量。按值捕获会在 lambda 表达式创建时复制变量的值,而按引用捕获则直接引用外部变量。
4. 复杂的表达式;返回类型最好明确指定。
5. 在 lambda 表达式内部添加适当的异常处理机制以确保程序的健壮性。
6. 在多线程环境中使用 lambda 表达式时,需要格外小心,确保正确地同步共享数据,以避免竞态条件和数据竞争问题。??(我还只小懂呢,先记着)

[捕获列表] (参数列表) -> 返回类型 {
    // lambda 表达式的主体
}

例子:

auto print = []() {cout << "demo"; };
auto print1 = [](int a) {cout << a; };
auto print2 = [](int a, int b)->void{cout << a << b; };
auto add = [](int a, int b) -> int { return a + b; };
int x = 10; auto printX = [=]() {cout << x; };

//1. 使用lambda表达式过滤vector中的偶数:
std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};  
auto is_even = [](int x){ return x % 2 == 0; };  
vec.erase(std::remove_if(vec.begin(), vec.end(), is_even), vec.end());  
for (auto i : vec) {  
    std::cout << i << " ";  
}   

//2. 使用lambda表达式对map中的键进行排序:
std::map<std::string, int> myMap;  
myMap["apple"] = 1;  
myMap["banana"] = 2;  
myMap["cherry"] = 3;  
myMap["date"] = 4;  
myMap["elderberry"] = 5;  
auto compare = [](const std::pair<const std::string, int>& a, const std::pair<const std::string, int>& b){ return a.first < b.first; };  
std::sort(myMap.begin(), myMap.end(), compare);  
for (auto& x : myMap) {  
    std::cout << x.first << ": " << x.second << std::endl;  
}  

//3. 使用lambda表达式实现函数对象:
std::vector<int> nums{1, 2, 3, 4, 5, 6, 7, 8, 9};  
auto square = [](int x){ return x * x; };  
std::transform(nums.begin(), nums.end(), nums.begin(), square);  
for (auto i : nums) {  
    std::cout << i << " ";  
}  

//4. 计算整数参数的总和:
auto sum = [](int a, ...) {  
    int total = a;  
    va_list args;  
    va_start(args, a);  
    while (true) {  
        int next = va_arg(args, int);  
        if (next <0) {  
            break;  
        }  
        total += next;  
    }  
    va_end(args);  
    return total;  
};  
int result = sum(1, 2, 3, 4, 5, -1); // result = 15

//5. 异常处理:
int divisor = 0;
auto divide = [&divisor](int dividend) {
    try {
        if (divisor == 0) {
            throw std::runtime_error("Division by zero.");
        }
        return dividend / divisor;
    } catch (const std::exception& e) {
        std::cerr << "Exception caught: " << e.what() << std::endl;
        return 0;
    }
};
int result = divide(10);
std::cout << "Result: " << result << std::endl;

20230920 加

C++ lambda 表达式是一种功能强大的编程工具,它允许您在代码中创建匿名函数或闭包。Lambda 表达式背后的原理是 C++11 引入的一项功能,它结合了以下几个重要概念和技术:

  1. 匿名函数:Lambda 表达式本质上是匿名函数,它允许您在需要的地方定义函数,而无需提前命名函数或在全局范围内定义函数。
  2. 闭包:Lambda 表达式是闭包,它可以捕获其所在作用域的变量。这意味着 Lambda 表达式可以访问并操作在其定义位置之外的变量,包括局部变量、函数参数、全局变量等。
  3. 函数对象(Functor):Lambda 表达式本质上创建了一个函数对象(也称为函数符或函数器),它可以像普通函数一样调用。这个函数对象具有与 Lambda 表达式相同的行为,并且可以传递给其他函数或存储为变量。
  4. 类型推导:Lambda 表达式可以使用类型推导来自动推断参数和返回值的类型,这使得代码更加简洁并且减少了需要显式指定类型的需要。

Lambda 表达式的运行原理包括以下关键步骤:

  1. Lambda 表达式被编译器转化为一个匿名函数对象。
  2. 如果在捕获列表中指定了变量,编译器会为该匿名函数对象生成一个特殊的数据成员,以便在运行时捕获和使用这些变量的值。
  3. Lambda 表达式内的代码被编译成与普通函数相似的代码,可以在需要的地方调用该函数对象。
  4. 在运行时,Lambda 表达式内的捕获变量的值将与函数对象一起传递,以便在 Lambda 主体内使用。

例如

//例子一
auto lambda = [](int x, int y) -> int {
    return x + y;
};
//编译器将创建一个匿名的函数对象类伪代码:
class __lambda_function {
public:
    int operator()(int x, int y) const {
        return x + y;
    }

private:
    // 捕获的变量(如果有的话)
};

这个`__lambda_function`类中有一个`operator()`成员函数,它执行Lambda表达式内部的代码。变量`lambda`实际上是一个对象,可以像函数一样调用,例如:
int result = lambda(3, 4); // 调用Lambda表达式,result将包含7
在运行时,Lambda表达式内的代码将由这个匿名函数对象执行,并且如果有捕获的外部变量,它们也将在这个函数对象内进行管理。

//例子二:
int x = 10;
auto lambda = [x](int a) {
    return x + a;
};
//编译器将创建一个匿名的函数对象类伪代码:
class LambdaFunction {
private:
    int captured_x; // 存储捕获的变量 x
public:
    LambdaFunction(int x) : captured_x(x) {}

    int operator()(int a) const {
        return captured_x + a;
    }
};

对函数指针和指针函数补充:

函数指针 vs 指针函数:
函数指针是一个指向函数的指针变量。
指针函数是一个返回函数指针的函数。
用途:
函数指针用于存储函数的地址以便在运行时调用它。
指针函数用于根据条件返回不同的函数指针,允许在运行时选择要调用的函数。

函数指针:
函数指针是指向函数的指针变量。它存储了函数的地址,允许您在运行时动态选择要调用的函数。函数指针通常用于实现回调函数、构建函数表、创建通用代码等情况。

指针函数:
指针函数是一个返回指针的函数。它是一个函数,其返回类型是指针,该指针可以指向某种类型的数据。指针函数用于创建并返回指向某个数据对象的指针。文章来源地址https://www.toymoban.com/news/detail-709884.html

//函数指针:
int add(int a, int b) {
    return a + b;
}
int subtract(int a, int b) {
    return a - b;
}
int (*funcPtr)(int, int);
funcPtr = add; // 将函数指针设置为指向add函数
//funcPtr = subtract;
int result = funcPtr(5, 3); // 调用add函数,result将包含8

//指针函数:
例子一:
// 声明一个指针函数,返回类型是指向整数的指针
int* createIntPointer(int value) {
    int* ptr = new int(value);
    return ptr;
}

// 使用指针函数创建指针对象
int* pointer = createIntPointer(42);
例子二:
int* test(int a, int b) {
    int c = a + b;
    return &c;
}
int main() {
    int* testvalue =test(2,3);
    std::cout << *testvalue;//5
}

//综合例子:
#include <iostream>
// 函数指针:接受两个整数参数并返回整数
int (*add)(int, int);

// 指针函数:返回指向整数的指针
int* createIntPointer(int value) {
    int* ptr = new int(value);
    return ptr;
}

// 函数:计算两个整数的和
int sum(int a, int b) {
    return a + b;
}

int main() {
    // 分配一个整数对象并返回其指针
    int* pointer = createIntPointer(42);
    // 将函数的地址分配给函数指针
    add = &sum;   
    // 使用函数指针调用函数
    int result = add(3, 5);
    std::cout << "Result of add(3, 5): " << result << std::endl;
    std::cout << "Pointer value: " << *pointer << std::endl;
    // 释放动态分配的内存
    delete pointer; 
    return 0;
}

我cao,莫名觉得有点~昂。
永远的新手,请多多指教喽


//结合上面 自己写个Demo,运行就知道了
内容参考:https://www.zhihu.com/question/41940148
int  m = 5;	
auto f = [](int x)->int { return x; };      //准函数lambda表达式
int (*p)(int) = f;  //函数指针f赋值给函数指针变量p	
auto g = [m](int x)mutable->int{  ++m;return m; }; //准对象lambda表达式	
//p = g;             //错误:g是一个准对象,不能赋值给函数指针p

到了这里,关于C++系列十:日常学习-Lambda表达式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ 中的Lambda表达式

    Lambda 表达式 (lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是 一个匿名函数,即没有函数名的函数 。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。 闭包 就是能够读取其他函数内部变量

    2024年02月09日
    浏览(50)
  • 【C++】Lambda表达式的使用

    例如: 了解Lambda的优点 掌握Lambda表达式的使用 了解Lambda表达式的底层原理 Lambda表达式的语法 lambda表达式的底层实现涉及到闭包(Closure)的概念。闭包是一个函数对象,它可以捕获外部作用域中的变量,并在其生命周期内访问和修改这些变量。lambda表达式的底层实现就是通

    2024年02月14日
    浏览(45)
  • C++复习笔记--Lambda表达式

    ① [] 用于捕获变量,一般用于使用和修改外部的变量,可以为空; ② (int a, int b) 表示参数列表,可以省略; ③ - int 定义返回类型,一般可以省略,让编译器自动推断; ④ auto f 表示将定义的 lambda 表达式赋值给对象 f,auto 用于自动推断类型; 基本用法如下: ① 使用和修

    2024年02月16日
    浏览(60)
  • C++的lambda表达式(匿名函数)

    从C++11开始,C++也支持使用lambda表达式(匿名函数)。Lambda表达式是一种便捷的方式,可以定义一个函数对象,而无需使用显式的函数对象类型或函数指针语法。 C++中的 lambda表达式的基本语法如下: 其中各个部分的含义如下: capture list :用于指定所捕获的外部变量列表。可

    2024年02月08日
    浏览(46)
  • 【C++】C++11——lambda表达式

    我们之前都是通过函数指针、仿函数的方式可以像函数使用的对象,在C++11之后,就有了Lambda表达式 为了实现一个比较算法, 都要重新去写一个类,如果每次比较的逻辑不一样,还要去实现多个类,特别是相同类的命名,看代码的人就遭殃了,非常的烦,这些都非常地不方便

    2024年01月17日
    浏览(52)
  • C++ Lambda表达式的常见用法

    ⭐️我叫忆_恒心,一名喜欢书写博客的在读研究生👨‍🎓。 如果觉得本文能帮到您, 麻烦点个赞 👍呗! 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三连支持一下呗。👍⭐️❤️ 作为C++11的新特性的Lambada表达式本身

    2024年01月16日
    浏览(71)
  • 【C++】C++11语法 ~ lambda 表达式

    (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是 Scort 目前状态:大三非科班啃C++中 🌍博客主页:张小姐的猫~江湖背景 快上车🚘,握好方向盘跟我有一起打天下嘞! 送给自己的一句鸡汤🤔: 🔥真正的大师永远怀着一颗学徒的心 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏 🎉🎉

    2024年01月20日
    浏览(61)
  • 【Java系列】JDK 1.8 新特性之 Lambda表达式

    Lambda是一个匿名函数,我们可以将Lambda表达式理解为一段可以传递的代码(将代码像数据一样传递)。使用它可以写出简洁、灵活的代码。作为一种更紧凑的代码风格,使java语言表达能力得到提升。 结果: ​19:43:39.303 [main] INFO com.chen.test.JAVA8Features.Demo01 - 我是没有使用Lambda表

    2024年02月22日
    浏览(49)
  • Java学习——lambda表达式

    什么是Lambda表达式? 可以将Lambda表达式理解为一个匿名函数; Lambda表达式允许将一个函数作为另外一个函数的参数; 我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码作为实参),也可以理解为函数式编程, 将一个函数作为参数进行传递 。 为什么要引入Lambda表

    2024年02月04日
    浏览(65)
  • C++ lambda表达式函数递归调用简单写法实现

    在C++11中,lambda表达式函数递归往往会带上 functional 头文件。书写形式如下: 还有相对简单点的第二种写法(C++14): 对于第二种, auto fib 的作用是为了在 lambda 表达式内部能够递归调用自身。在 C++14 中,lambda 表达式默认是无法直接递归调用的,因为在 lambda 内部无法访问到

    2024年02月15日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包