?? 問題
描述
記得去年立了一個重學(xué)C++新特性的flag,可是真的太忙了,大部分精力都花在全棧上了,今年開始看一些開源源碼,發(fā)現(xiàn)各種奇怪的語法,根本看不懂,
不學(xué)不行
了。而且接觸了很多語言后,發(fā)現(xiàn)新特性的確能提高開發(fā)效率
,所以還是重新學(xué)習(xí)下C++吧。
環(huán)境
版本號 | 描述 | |
---|---|---|
文章日期 | 2023-06-09 | |
操作系統(tǒng) | Win11 - 21H2 - 22000.1335 | |
C++在線工具 | https://c.runoob.com/compile/12/ | |
1?? 什么是Lambda表達式
Lambda表達式是C++11中新增的一種
函數(shù)對象
,它可以方便地定義一個匿名函數(shù),從而簡化代碼的編寫。
Lambda表達式的本質(zhì)是一個可調(diào)用對象
,可以像函數(shù)一樣被調(diào)用,也可以作為函數(shù)參數(shù)或返回值。
Lambda 表達式的各個部分
下面是作為第三個參數(shù) std::sort() 傳遞給函數(shù)的簡單 lambda:
#include <algorithm> #include <cmath> void abssort(float* x, unsigned n) { std::sort(x, x + n, // 下面是一個簡單的 `Lambda 表達式` [](float a, float b) { return (std::abs(a) < std::abs(b)); } ); }
下圖顯示了 lambda 語法的各個部分:
捕獲列表
:(capture list)(在 C++ 規(guī)范中也稱為 Lambda 引導(dǎo)。)參數(shù)列表
:(parameters list)(可選)。 (也稱為 Lambda 聲明符)mutable 規(guī)范
:(可選)。異常說明
:exception-specification(可選)。返回類型
:trailing-return-type(可選)。Lambda 體
:也就是函數(shù)體。![]()
引用大佬的一張圖:
2?? 優(yōu)缺點
優(yōu)點
- 簡化代碼:Lambda表達式可以將一些冗長的代碼簡化為一行代碼,使代碼更加簡潔。
- 提高可讀性:Lambda表達式可以使代碼更加易讀,減少了一些冗余的代碼,使代碼更加簡潔明了。
- 提高可維護性:Lambda表達式可以使代碼更加易于維護,因為它可以將一些復(fù)雜的邏輯封裝在一個方法中,使代碼更加模塊化。
缺點
- 學(xué)習(xí)成本高:Lambda表達式需要一定的學(xué)習(xí)成本,需要理解函數(shù)式編程的概念和Lambda表達式的語法。
- 可讀性降低:有時候Lambda表達式可能會使代碼變得更加難以理解,特別是當(dāng)Lambda表達式嵌套時。
- 性能問題:Lambda表達式可能會影響程序的性能,因為它需要創(chuàng)建一個新的對象來表示Lambda表達式。但是,這種影響通常是微不足道的,只有在極端情況下才會有明顯的性能問題。
3?? 使用場景
Lambda表達式可以用于任何需要函數(shù)對象的場景,例如:
- STL算法中需要傳遞函數(shù)對象的地方,如
std::sort
、std::for_each
等;- STL容器中需要傳遞比較函數(shù)的地方,如
std::set
、std::map
等;- 多線程編程中需要傳遞回調(diào)函數(shù)的地方,如
std::thread
、std::async
等。
在線C++工具
為了方便演示,找了個在線C++工具 https://c.runoob.com/compile/12/ ,可以直接在網(wǎng)頁中運行C++代碼。
效果圖如下:
STL算法庫
find_if
應(yīng)用實例
#include <iostream>
#include <deque>
#include <algorithm>
using namespace std;
int main()
{
int x = 5;
int y = 10;
deque<int> coll = { 1, 3, 19, 5, 13, 7, 11, 2, 17 };
auto pos = find_if(coll.cbegin(), coll.cend(), [=](int i) {
return i > x && i < y;
});
cout << "find " << (pos != coll.end() ? "success" : "failed");
return 0;
}
sort
實例,用于對一個整數(shù)數(shù)組進行排序:
以上代碼中,Lambda表達式[](int a, int b) { return a < b; }
用于指定排序規(guī)則,即按照升序排列。
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
// 使用Lambda表達式對vec進行排序
std::sort(vec.begin(), vec.end(), [](int a, int b) { return a < b; });
// 輸出排序后的結(jié)果
// 1 1 2 3 3 4 5 5 5 6 9
for (auto x : vec)
{
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
STL容器中需要傳遞比較函數(shù)
在線工具不能正常運行:
#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
int LambdaContainer()
{
auto fc = [](const std::string& a, const std::string& b) {
return a.length() > b.length();
};
std::map<std::string, int, decltype(fc)> myMap = { {"apple", 5}, {"banana0", 10}, {"orange", 15} };
// 使用迭代器遍歷map
std::cout << "使用迭代器遍歷map:" << std::endl;
for (auto it = myMap.begin(); it != myMap.end(); ++it) {
std::cout << it->first << " : " << it->second << std::endl;
}
// 需要C++20支持
std::map < std::string, int, decltype([](const std::string& a, const std::string& b) {
return a.length() < b.length();
}) > myMap2 = { {"apple", 5}, {"banana0", 10}, {"orange", 15} };
// 使用范圍for循環(huán)遍歷map
std::cout << "\n\n使用范圍for循環(huán)遍歷map:" << std::endl;
for (const auto& [key, value] : myMap2) {
std::cout << key << " : " << value << std::endl;
}
return 0;
}
針對
myMap
,需要C++17
支持
針對myMap2
,decltype
中使用lambda需要C++20
支持
多線程示例
在線工具不能正常運行:
#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
int main()
{
// vector 容器存儲線程
std::vector<std::thread> workers;
for (int i = 0; i < 5; i++)
{
workers.push_back(std::thread([]()
{
std::cout << "thread function\n";
}));
}
std::cout << "main thread\n";
// 通過 for_each 循環(huán)每一個線程
// 第三個參數(shù)賦值一個task任務(wù)
// 符號'[]'會告訴編譯器我們正在用一個匿名函數(shù)
// lambda函數(shù)將它的參數(shù)作為線程的引用t
// 然后一個一個的join
std::for_each(workers.begin(), workers.end(), [](std::thread &t)
{
t.join();
});
return 0;
}
4?? Lambda表達式與函數(shù)指針的比較
Lambda表達式與函數(shù)指針類似,都可以用于定義函數(shù)對象。但是,Lambda表達式相比函數(shù)指針具有以下優(yōu)點:
- Lambda表達式可以捕獲外部變量,從而方便地訪問外部環(huán)境;
- Lambda表達式可以定義在函數(shù)內(nèi)部,從而避免了命名沖突的問題;
- Lambda表達式可以使用auto關(guān)鍵字自動推導(dǎo)返回值類型,從而簡化代碼。
5?? 捕獲列表
Lambda表達式的捕獲列表用于指定Lambda表達式中使用的外部變量。捕獲列表可以為空,也可以包含以下內(nèi)容:
[]
:不捕獲任何外部變量;[&]
:以引用方式捕獲所有外部變量;[=]
:以值方式捕獲所有外部變量;[var1, var2, ...]
:指定捕獲特定的外部變量;[&, var1, var2, ...]
:以引用方式捕獲所有外部變量,并指定捕獲特定的外部變量;[=, &var1, &var2, ...]
:以值方式捕獲所有外部變量,并以引用方式捕獲特定的外部變量。
6?? 返回值類型
Lambda表達式的返回值類型可以顯式指定,也可以使用auto關(guān)鍵字自動推導(dǎo)。如果Lambda表達式的函數(shù)體只有一條語句,且該語句的返回值類型可以自動推導(dǎo),則可以省略返回值類型和return關(guān)鍵字。
7?? 工作原理
編譯器會把一個Lambda表達式生成一個匿名類的匿名對象,并在類中重載函數(shù)調(diào)用運算符,實現(xiàn)了一個operator()方法。
以auto print = []{cout << "Hello World!" << endl; };
為例,編譯器會把上面這一句翻譯為下面的代碼:文章來源:http://www.zghlxwxcb.cn/news/detail-477382.html
class print_class
{
public:
void operator()(void) const
{
cout << "Hello World!" << endl;
}
};
// 用構(gòu)造的類創(chuàng)建對象,print此時就是一個函數(shù)對象
auto print = print_class();
ps: 仿函數(shù)(functor)又稱為函數(shù)對象(function object)是一個能行使函數(shù)功能的類。仿函數(shù)的語法幾乎和我們普通的函數(shù)調(diào)用一樣,不過作為仿函數(shù)的類,都必須重載operator()運算符,仿函數(shù)與Lamdba表達式的作用是一致的。
stl中含有大量類似的對象,如std::less
:文章來源地址http://www.zghlxwxcb.cn/news/detail-477382.html
?? 參考資料
- 微軟Lambda教程 https://learn.microsoft.com/zh-cn/cpp/cpp/lambda-expressions-in-cpp?view=msvc-170
- C++ Lambda表達式詳解 https://blog.csdn.net/qq_37085158/article/details/124626913
- 在線C++工具 https://c.runoob.com/compile/12/
- 在線C++工具2 https://www.json.cn/runcode/run_cpp920/
到了這里,關(guān)于【C++】 Lambda表達式詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!