c++中lambda函數是作爲c++11新特新添加到c++中的,其主要是以匿名函數捕獲scope內變量的方式構造閉包(closure)。相關標準參考:c++ reference
下面以若干不相干的簡短程序的方式總結一下lambda的基本使用方式(暫未涉及lambda的c++17/20的特性)
[lambda.h]
#include<iostream>
#pragma once
using namespace std;
void funcExt();
class Lamb{
private:
int aa =20;
int bb =30;
public:
Lamb();
~Lamb();
void show();
void f(){
auto fun10 = [this](){this->show();};
fun10();
}
};
---------------------------------------------------------------------------------------------------------
[lambda_ext.cpp]
#include "lambda.h"
auto func =[](){cout<<"funcExt result."<<endl;};
void funcExt(){
func();
}
Lamb::Lamb(){};
Lamb::~Lamb(){};
void Lamb::show(){
cout<<aa+bb<<endl;
}
---------------------------------------------------------------------------------------------------------
[lambda.cpp]
// [ captures ] <tparams>(optional)(C++20) (params) specifiers(optional) exception attr
// -> ret requires(optional)(C++20) { body }
// tparams 模板形參列表,提供名稱給泛型lambda的模板形參(c++20)
// specifiers [mutable/constexpr(c++17)]
// [ captures ] ( params ) -> ret { body }
// [captures](params) { body }
// [ captures ] { body }
// 僅若不使用specifiers、exception、attr或ret之一才能使用此形式。
#include <iostream>
#include <typeinfo>
#include "lambda.h"
int ext = 10 ;
int main()
{
// normal
auto func1 = []() { cout << "func1:hello world." << endl; };
func1();
// var func1 type Z4mainE3$_1 ,only auto
// ignore params
auto func2 = [] { cout << "func2:haha." << endl; };
func2();
// spec ret
auto func3 = []() -> int { return 1.0; };
cout << "func3 ret:" << typeid(func3()).name() << "=" << func3() << endl;
// mutil return spec ret
auto func4 = [](int i) -> int {
if(i>10) return 1;
else return 2.3;
};
cout << "func4 ret:" << typeid(func4(5)).name() << "=" << func4(5) << endl;
funcExt();
// normal para_list lambda,compared to func9() and func7()
int a=5,b=6;
auto func5 = [](int& x,int& y){x++,y++;return x+y;};
cout << "func5 sum:" << func5(a,b) << " a:" << a << " b:" << b << endl;
// capture
// capture opt: -- only capture non-static var
// blank 不捕獲任何變量
// = 捕獲外部作用域所有自動變量,按值傳遞給函數體,且包含this捕獲,如果存在對象
// & 捕獲外部作用域所有自動變量,按引用傳遞給函數體,且包含this捕獲,如果存在對象
// this 按引用捕獲當前對象
{
int c=7;
{
int e=9;
{int f=11;/*static int ext=10;*/}
auto func6 = [a, c, e, ext/*f*/]() { // capture f is illegal,not in lambda scope
// ext is static ,not captured, but capture list allowed -- warning
cout<<"func6 a:"<<a<<" c:"<<c<<" e:"<<e<<" ext:"<<ext<</*" f:"<<f<<*/endl;};
func6();
}
auto func7 = [=,&a](){ // capture e is illegal,not in lambda scope
cout<<"func7 a:"<<a<<" c:"<<c<</*" e:"<<e<<*/" ext:"<<ext<<endl;
a++;/*c++;*/}; // var copy ,change not access
func7();
cout<<"a++: "<<a<<endl;
auto func8 = [](){
cout<</*"a:"<<a<<" c:"<<c<<" e:"<<e<<*/"func8 ext:"<<ext<<endl;
ext =11;};
func8();
cout<<"access static ext+1: "<<ext<<endl;
// lambda operator() is const(copy capture) , val capture non-modifiable
auto func9 = [=]()mutable{
c++;};
cout<<"c: "<<c<<endl;
func9();
cout<<"func9 c++: "<<c<<endl; // capture var copy
}
Lamb func;
func.f();
// diff between = and &
auto func11 = [=](){return a;};
cout<<"a: "<<a;
a++;
cout<<" func11 a++: "<<func11()<<endl;
auto func12 = [&](){return b;};
cout<<"b: "<<b;
b++;
cout<<" func12 b++: "<<func12()<<endl;
}
---------------------------------------------------------------------------------------------------------
[運行結果]
func1:hello world.
func2:haha.
func3 ret:i=1
func4 ret:i=2
funcExt result.
func5 sum:13 a:6 b:7
func6 a:6 c:7 e:9 ext:10
func7 a:6 c:7 ext:10
a++: 7
func8 ext:10
access static ext+1: 11
c: 7
func9 c++: 7
50
a: 7 func11 a++: 7
b: 7 func12 b++: 8
說明:
func1 – lambda基本用法,類型原因需要auto自動推到返回類型
func2 – 沒有特殊用法比如限定符、異常等時,可以忽略圓括號用法
func3 – 指定lambda函數返回值
func4 – 多種不同類型返回值lambda函數時一定需要指定返回類型
func5 – 指定參數列表,以及對原始數據的修改情況,跟一般函數無異
func6 – 按變量複製的方式捕獲scope內變量,需要注意的是,捕獲變量只能是lambda作用域外的自動變量,f在作用域內,不能捕獲、ext屬於靜態變量,本身不能被捕獲,但是在捕獲列表中捕獲報錯,gcc7.x編譯僅僅warning,但是作爲靜態變量,是能夠在lambda函數中直接訪問的(但不是因爲ext靜態變量作用於整個項目,對比func8,雖然自動變量a,c,e在func8作用域之外,但沒有指定捕獲列表是不能直接訪問的)
func7 – ①以全部捕獲的方式對變量進行捕獲 ②lambda默認爲const成員函數,不能對按值傳遞的變量進行修改
func8 – 不指定任何捕獲時,能過訪問靜態變量
func9 – 通過限定符mutable,使按值傳遞的變量能被修改,但因爲是副本原因,能對變量進行修改,但修改對原數據並沒有什麼卵影響
func10、func11 – this捕獲當前對象用法
func12 – 對比一下引用方式捕獲跟按值捕獲的小區別—-按值捕獲在創建lambda時就將變量複製捕獲,造成調用時數據內容產生延遲