论C++的lambda是函数还是对象

先说结论:

  • 对于有捕获的lambda,其等价于对象。
  • 对于没有任何捕获的lambda,其等价于函数!

首先,很多C++程序员从lambda 用法上反推容易发现是对象,因为lambda可以捕获!这是函数做不到的。的确,比如:

int n = 100;
auto foo = [n](int a) {
    return a > n;
};
cout<< foo(99);

如果编译器要实现foo,大致类比这种写法(可能真实的实现细节不是这样,但思路类似)∶

struct Foo {
    Foo(int i) {n=i;}
    bool operator()(int a) {
        return a > n;
    }
private:
    int n;
};
...
int n = 100;
Foo foo(n);
cout<< foo(99);

如果是引用捕获了变量,那么struct内有一个指针成员持有被引用捕获的变量的地址。

比如:

set<int> ns = {100, 200, 300};
auto foo = [&ns](int a) {
    return ns.find(a);
};
cout<< foo(99);

大致等价于:

struct Foo {
    Foo(set<int>* p) {p_ns = p;}
    bool operator()(int a) {
        auto &ns = *p-ns;
        return ns.find(a);
    }
private:
    set<int>* p_ns;
};
...
set<int> ns = {100, 200, 300};
Foo foo(&ns);
cout<< foo(99);

然而……这并不是全部!
在没有捕获任何东西的时候,lambda其实是等价于普通的函数的!可以用Linux C中函数pthread_create()来验证!它只能接收一个参数是void*,返回值也是void*的回调函数。

神奇的是,无参的lambda也可以被pthread_create()使用!

using namespace std;
struct A {
    void* operator()(void*) {
        cout<<"xxxx"<<endl;
        return nullptr;
    }
};
int main() {
    A a;
    a(NULL);
    pthread_t t;
    //pthread_create(&t, NULL, a, NULL); // 编译失败
    auto cb = [](void*)->void* {
        cout<<"xxxx"<<endl;
        return nullptr;
    };
    pthread_create(&t, NULL, cb, NULL); // 编译通过
    pthread_join(t, NULL);
    return 0;
}

上面代码还可以再改一下,让cb去捕获一个变量, 比如:

auto cb = [&](void*)->void* {
        cout<<"xxxx"<<endl;
        return nullptr;
    };
    pthread_create(&t, NULL, cb, NULL);

这时,给pthread_create()传入cb同样会编译失败!错误信息:

cb.cpp: In function ‘int main()':
cb.cpp:23:30: error: cannot convert ‘main()::<lambda(void*)>' to ‘void* (*)(void*)'
   23 |     pthread_create(&t, NULL, cb, NULL);
      |                              ^~
      |                              |
      |                              main()::<lambda(void*)>
In file included from /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:35,
                 from /usr/include/x86_64-linux-gnu/c++/9/bits/gthr.h:148,
                 from /usr/include/c++/9/ext/atomicity.h:35,
                 from /usr/include/c++/9/bits/ios_base.h:39,
                 from /usr/include/c++/9/ios:42,
                 from /usr/include/c++/9/ostream:38,
                 from /usr/include/c++/9/iostream:39,
                 from cb.cpp:1:
/usr/include/pthread.h:200:15: note:   initializing argument 3 of ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)'
  200 |       void *(*__start_routine) (void *),
      |       ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~

这其实也不难理解,C++在lambda的设计上也贯彻着零开销 (Zero Overhead)原则,也就是C++不在性能上干多余的事,显然函数比对象开销更小。所以即使同为lambda,在有无捕获的时候,其底层实现其实是截然不同的!

到此这篇关于论C++的lambda是函数还是对象的文章就介绍到这了,更多相关C++中的lambda内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++中的Lambda表达式详解

    我是搞C++的 一直都在提醒自己,我是搞C++的:但是当C++11出来这么长时间了,我却没有跟着队伍走,发现很对不起自己的身份,也还好,发现自己也有段时间没有写C++代码了.今天看到了C++中的Lambda表达式,虽然用过C#的,但是C++的,一直没有用,也不知道怎么用,就可怜的连Lambda语法都看不懂.好了,这里就对C++中的Lambda进行一个简单的总结,就算是对自己的一个交代,我是搞C++的,我是一个C++ programmer. 一段简单的Code 我也不是文艺的人,对于Lambda的

  • C++中的Lambda函数详解

    目录 一 函数语法 二 函数应用 1.在普通函数中使用 2.在qt信号槽中使用 3.在std::sort排序函数中的使用 三 总结 一 函数语法 我们平时调用函数的时候,都是需要被调用函数的函数名,但是匿名函数就不需要函数名,而且直接写在需要调用的地方,对于以前没用过的小伙伴来说,第一眼看见了这语法可能很迷惑. C++11的基本语法格式为: [capture](parameters) -> return_type { /* ... */ } (1) [capture] :[]内为外部变量的传递方

  • 基于C++ Lambda表达式的程序优化

    什么是Lambda? C++ 11加入了一个非常重要的特性--Lambda表达式.营里(戴维营)的兄弟都对Objective-C很熟悉,许多人多block情有独钟,将各种回调函数.代理通通都用它来实现.甚至有人选择用FBKVOController.BlocksKit等开源框架将KVO.控件事件处理都改为通过block解决.原因就是简单.方便.直观,函数的定义和使用出现在同一个地方.这里的Lambda表达式实际上和block非常类似,当然如果你用它和Swift语言的闭包比较,那就是一回事了. 这是

  • 论C++的lambda是函数还是对象

    先说结论: 对于有捕获的lambda,其等价于对象. 对于没有任何捕获的lambda,其等价于函数! 首先,很多C++程序员从lambda 用法上反推容易发现是对象,因为lambda可以捕获!这是函数做不到的.的确,比如: int n = 100; auto foo = [n](int a) {     return a > n; }; cout<< foo(99); 如果编译器要实现foo,大致类比这种写法(可能真实的实现细节不是这样,但思路类似)∶ struct Foo {    

  • python中lambda匿名函数详解

    在Python中,不通过def来声明函数名字,而是通过lambda关键字来定义的函数称为匿名函数 关键字lambda表示匿名函数 语法 lambda 参数:表达式 先写lambda关键字,然后依次写匿名函数的参数,多个参数中间用逗号连接,然后是一个冒号,冒号后面写返回的表达式 lambda函数比普通函数更简洁 匿名函数有个好处:函数没有名字,不必担心函数名冲突 匿名函数与普通函数的对比 : def sum_func(a, b, c): return a + b + c sum_lambda =

  • C++11 lambda(匿名函数)表达式详细介绍

    目录 前言 概念及基本用法 捕获变量 lambda表达式类型 声明式的编程风格 总结 前言 Lambda(匿名函数)表达式是C++11最重要的特性之一,lambda来源于函数式编程的概念,也是现代编程语言的一个特点. 优点如下: 声明式编程风格:就地匿名定义目标函数或函数对象,有更好的可读性和可维护性. 简洁:不需要额外写一个命名函数或函数对象,,避免了代码膨胀和功能分散. 更加灵活:在需要的时间和地点实现功能闭包. 概念及基本用法 lambda表达式定义了一个匿名函数,并且可以捕获一定范围内的

  • Python lambda 匿名函数优点和局限性深度总结

    目录 什么是 Python 中的 Lambda 函数 Python 中的 Lambda 函数如何工作 Lambda 函数在 Python 中的应用 带有 filter() 函数的 Lambda 带有 map() 函数的 Lambda 带有 reduce() 函数的 Lambda Python 中 Lambda 函数的优缺点 优点 缺点 总结 什么是 Python 中的 Lambda 函数 今天我们来学习 Python 中的 lambda 函数,并探讨使用它的优点和局限性 Let's do it!

  • Python lambda匿名函数深入讲解

    目录 一,Python中lambda函数的语法 二,两个注意点 三,lambda 应用 一,Python中lambda函数的语法 lambda 函数在 Python 编程语言中使用频率非常高,使用起来非常灵活.巧妙:lambda 函数是一个匿名函数(即,没有名称定义),它可以接受任意数量的参数,但与普通函数不同,它只计算并返回一个表达式 Python 中的 lambda 函数使用以下语法表达: lambda [arg1 [,arg2,.....argn]]:expression ""&

  • 详解JavaScript的闭包、IIFE、apply、函数与对象

    目录 一.闭包(Closure) 1.1.闭包相关的问题 1.2.理解闭包 二.对象 2.1.对象常量(字面量) 2.2.取值 2.3.枚举(遍历) 2.4.更新与添加 2.5.对象的原型 2.6.删除 2.7.封装 三.函数 3.1.参数对象 (arguments) 3.2.构造函数 3.3.函数调用 3.3.1.call 3.3.2.apply 3.3.3.caller 3.3.4.Callee 3.5.立即执行函数表达式 (IIFE) 3.5.1.匿名函数与匿名对象 3.5.2.函数与函数

  • JavaScript中重名的函数与对象示例详析

    前言 本文主要给大家介绍了关于JavaScript中重名的函数与对象的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. JavaScript 允许重复声明变量,后声明的覆盖之前的. var a = 1; var a = 'x'; console.log(a); //输出'x' JavaScript允许重复定义函数. JavaScript没有重载这个概念,它仅依据函数名来区分函数. 后定义的同名函数覆盖之前的,与参数无关. function test() { consol

  • javascript用函数实现对象的方法

    本文实例讲述了javascript用函数实现对象的方法.分享给大家供大家参考.具体实现方法如下: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>利用函数实现对象(重要)</title&g

  • python ---lambda匿名函数介绍

    lambda特性:"一个语法,三个特性,四个用法" 一个语法 在Python中,lambda的语法是唯一的.其形式如下: lambda argument_list: expression 其中,lambda是Python预留的关键字,argument_list和expression由用户自定义.具体介绍如下. 1.这里的argument_list是参数列表.它的结构与Python中函数(function)的参数列表是一样的.具体来说,argument_list可以有非常多的形式.例如:

  • JS中的函数与对象的创建方式

    创建函数的三种方式 1.函数声明 function calSum1(num1, num2) { return num1 + num2; } console.log(calSum1(10, 10)); 2.函数表达式 var calSum2 = function (num1, num2) { return num1 + num2; } console.log(calSum2(10, 20)); 3.函数对象方式 var calSum3 = new Function('num1', 'num2',

随机推荐