C++:详解lamada表达式

发布于:2024-02-25 ⋅ 阅读:(86) ⋅ 点赞:(0)

C++中lamada表达式不是传统意义上的函数它是一个闭包函数对象或者说它是一个仿函数

lamada表达式结构

[捕获列表](可选参数列表)可选限定符 可选异常说明符 ->可选返回值类型{函数体}
  • 捕获方式:值捕获,引用捕获
  • 参数列表:当普通函数用即可,不同点在于它支持auto
  • 可选限定词:最常见的是mutable,它允许修改值捕获的变量
  • 异常说明符:可以使用noexcept
  • 返回值类型:可以省略支持auto

lamada表达式本质

#include<iostream>
int main(){
	int x=6,y=8;
	auto fun=[&]{return x+y;};
	int z=fun();
}

使用下面的指令查看GIMPLE中间代码

 g++ -fdump-tree-gimple -s lamada.cpp
cat lamada.cpp.005t.gimple 
main ()
{
  int D.39975;

  {
    int x;
    int y;
    struct __lambda0 fun;
    typedef struct __lambda0 __lambda0;
    int z;

    try
      {
        x = 6;
        y = 8;
        fun.__x = &x;
        fun.__y = &y;
        z = main()::<lambda()>::operator() (&fun);
      }
    finally
      {
        x = {CLOBBER};
        y = {CLOBBER};
        fun = {CLOBBER};
      }
  }
  D.39975 = 0;
  return D.39975;
}
main()::<lambda()>::operator() (const struct __lambda0 * const __closure)
{
  int D.39977;
  int & x [value-expr: __closure->__x];
  int & y [value-expr: __closure->__y];

  _1 = __closure->__x;
  _2 = *_1;
  _3 = __closure->__y;
  _4 = *_3;
  D.39977 = _2 + _4;
  return D.39977;
}
__static_initialization_and_destruction_0 (int __initialize_p, int __priority)
{
  if (__initialize_p == 1) goto <D.39979>; else goto <D.39980>;
  <D.39979>:
  if (__priority == 65535) goto <D.39981>; else goto <D.39982>;
  <D.39981>:
  std::ios_base::Init::Init (&__ioinit);
  __cxa_atexit (__dt_comp , &__ioinit, &__dso_handle);
  goto <D.39983>;
  <D.39982>:
  <D.39983>:
  goto <D.39984>;
  <D.39980>:
  <D.39984>:
}


_GLOBAL__sub_I_main ()
{
  __static_initialization_and_destruction_0 (1, 65535);
}

其实到这里已经明显了所谓的捕获参数列表就是告诉lamada表达式创建闭包类时要添加哪些变量,lamada表达式实际上就是这个闭包类的一个常成员函数。

无状态lamada表达式(捕获列表为空)

void fun(void(*)()){}
void g(){
	fun([]{};);//编译成功
}

C++对无状态lamada表达式处理比较宽泛,它可以隐式转化为函数指针

拓展

C++14 定义了广义捕获,它包含两种捕获方式

  • 简单捕获(值捕获,引用捕获,this捕获)
  • 初始化捕获,可以捕获表达式结果及自定义捕获变量名(C++ 14)
int main(){
	int x=5;
	[x=x+1]{return x;};
}

借助初始化捕获可以解决捕获的this被释放的问题:[=,tmp=*this]

C++ 14 实现了泛型lamada表达式,简单的来说就是参数列表开始支持auto

int main(){
	int x=5;
	auto fun=[](auto it){return it;};
	std::cout<<fun("haha")<<fun(123);
}

C++ 17 优化了常量lamada表达式和对*this的捕获常量lamada表达式的优化

C++20 引入了[=,this]来区分[-,*this]和[=]

C++20 添加了模板对lamada的支持,C++14 引入了auto但是auto与类型的交互能力较差,比如如果用auto完成部分特化的化甚至需要加入大量代码判断类型是否匹配

[]<template T>(T t){}

C++20 允许了无状态lamada表达式类型的构造和赋值

auto greater=[](auto x,auto y){return x>y;};
std::map<std::string,int,decltype(greater)>m1,m2;
m1=m2;

在C++20之前上述代码会有两处错误:

  1. decltype(greater),lamada表达式的默认构造被删除了因此无法完成类型推导
  2. m1=m2,lamada表达式拷贝构造关了,这里拷贝会失败
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到