0.問題導向
使用C++ STL實現訂單按照建立時間從小到大排查。
using Order = struct tagOrder{
unsigned int createTimspec;//建立時間戳
int id; //訂單號
int totalPrice; //總價
int status; //訂單狀態
int payType; //支付型別
};
void orderSortByTime(vector<Order>& orders)
{
sort(orders.begin(),orders.end());
}
這樣使用演算法庫的sort函式,編譯報錯:
error: no match for ‘operator<’ (operand types are ‘tagOrder’ and ‘tagOrder’)
43 | return *__it1 < *__it2; }.
編譯器只預設支援對基本資料型別的大小比較,例如int,long等。自定義資料結構需要自定義比較函式。
using Order = struct tagOrder{
unsigned int createTimspec;//建立時間戳
int id; //訂單號
int totalPrice; //總價
int status; //訂單狀態
int payType; //支付型別
};
int compare(Order a,Order b)
{
return a.createTimspec<b.createTimspec;
}
void orderSortByTime(vector<Order>& orders)
{
sort(orders.begin(),orders.end(),compare);
}
你發現沒有,這個自定義的函式compare很簡單,只有一行程式碼。但是每次呼叫仍然有函式呼叫的開銷,如果系統中有大量的呼叫需求,那麼函式呼叫對效能的影響就不能忽視了。
using Order = struct tagOrder{
unsigned int createTimspec;//建立時間戳
int id; //訂單號
int totalPrice; //總價
int status; //訂單狀態
int payType; //支付型別
};
void orderSortByTime(vector<Order>& orders)
{
sort(orders.begin(),orders.end(),[](Order a,Order b){return a.createTimspec<b.createTimspec;});
}
按照上圖方法也可以實現訂單排序功能,sort函式的第三個引數替代了自定義的compare函式,"[](Order a,Order b){return a.createTimspec<b.createTimspec;}",這串就是我們今天要學習的Lambda表示式。
1.Lambda表示式簡介
Lambda表示式,也稱為Lambada函式,實際是一個匿名函式(不需要定義函式名),主要的使用場景是函式入參,例如演算法函式和非同步函式。在C++中,從C++11開始引入Lambda表示式,之後在後面的C++14、C++17、C++20、C++23版本對Lambda表示式都有更新和擴充套件。這裡我們選擇最初的C++11版本,學習下Lambda表示式的基本語法和用法。
2.Lambda表示式語法
Lambda基本語法如下,包含捕獲、引數、修飾符、返回型別和實體五部分。其中,修飾符和返回型別是可選部分。下面結合例子學習這五部分組成。
[capture](parameters) modifiers -> return-type {body}
3.Captures
1>捕獲引用型別和值型別
int arg=10;
auto lambdaCap = [&arg] (){arg++;};//capture by reference
lambdaCap();
cout<<"arg="<<arg<<endl;//arg=11
return 0;
上圖是捕獲引用型別,不用解釋。
int arg=10;
auto lambdaCap = [arg](){arg++;};//capture by value
lambdaCap();
cout<<"arg="<<arg<<endl;
//編譯失敗
main.cpp:265:30: error: increment of read-only variable ‘arg’
上圖編譯失敗。
int arg=10;
auto lambdaCap = [arg]()mutable{arg++;};//capture by value
lambdaCap();
cout<<"arg="<<arg<<endl;//arg=10
增加mutable修飾符後編譯透過,修飾符後面介紹。
2>捕獲有效範圍內的所有變數
int arg=10;
auto lambdaCap = [=]()mutable{arg++;};//capture by value
lambdaCap();
cout<<"arg="<<arg<<endl;//arg=10
上圖是使用'='表示以值型別的方式捕獲有效範圍內的所有變數。
int arg=10;
auto lambdaCap = [&]()mutable{arg++;};//capture by value
lambdaCap();
cout<<"arg="<<arg<<endl;//arg=11
上圖是使用'&'表示以引用的方式捕獲有效範圍內的所有變數。
4.Parameters
auto lambdaAdd = [](int a,int b){return a+b;};
cout<<"sum="<<lambdaAdd(1,2)<<endl;//sum=3
這裡的引數和函式的入參類似,入參也可以有預設值。
auto lambdaAdd = [](int a,int b=1){return a+b;};//capture by value
cout<<"sum="<<lambdaAdd(1)<<endl;//sum=2
5.Body
實體部分類似普通函式的函式體,例如開端的訂單排序例子中的Body返回建立時間的大小。
void orderSortByTime(vector<Order>& orders)
{
sort(orders.begin(),orders.end(),[](Order a,Order b){return a.createTimspec<b.createTimspec;});
}
6.Modifiers
可選部分,可以透過修飾符設定Lambda匿名函式的屬性,例如在Captures部分我們用的mutable修飾符。還有noexcept、noreturn等。
int arg=10;
auto lambdaCap = [arg]()mutable{arg++;};//capture by value
lambdaCap();
cout<<"arg="<<arg<<endl;//arg=10
7.Return-Type
可選部分,如果不設定返回型別,則由編譯器根據程式碼邏輯自動判斷型別,例如上面的所有例子都是這樣。如果設定返回型別,則強制要求編譯器按照該型別返回。
auto lambdaAdd = [](int a,int b)->long{return (long)a+b;};
cout<<"sum="<<lambdaAdd(0x7FFFFFFF,0x1)<<endl;//sum=2147483648
8.總結
這裡只是簡單介紹了Lambda函式的產生以及基本的語法和使用場景,還有很多深奧的相關部分需要持續學習。日拱一卒無有盡,終不唐捐入海流。