小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

C++Lambda表達(dá)式詳解

 dafuweng2011 2023-03-11 發(fā)布于北京

Lambda表達(dá)式概述

Lambda表達(dá)式是現(xiàn)代C++在C ++ 11和更高版本中的一個(gè)新的語(yǔ)法糖 ,在C++11、C++14、C++17和C++20中Lambda表達(dá)的內(nèi)容還在不斷更新。 lambda表達(dá)式(也稱(chēng)為lambda函數(shù))是在調(diào)用或作為函數(shù)參數(shù)傳遞的位置處定義匿名函數(shù)對(duì)象的便捷方法。通常,lambda用于封裝傳遞給算法或異步方法的幾行代碼 。本文主要介紹Lambda的工作原理以及使用方法。

Lambda表達(dá)式定義

Lambda表達(dá)式示例

Lambda有很多叫法,有Lambda表達(dá)式、Lambda函數(shù)、匿名函數(shù),本文中為了方便表述統(tǒng)一用Lambda表達(dá)式進(jìn)行敘述。 ISO C++標(biāo)準(zhǔn)官網(wǎng)展示了一個(gè)簡(jiǎn)單的lambda表示式實(shí)例:

#include <algorithm>
#include <cmath>

void abssort(float* x, unsigned n) {
    std::sort(x, x + n,
        // Lambda expression begins
        [](float a, float b) {
            return (std::abs(a) < std::abs(b));
        } // end of lambda expression
    );
}

在上面的實(shí)例中std::sort函數(shù)第三個(gè)參數(shù)應(yīng)該是傳遞一個(gè)排序規(guī)則的函數(shù),但是這個(gè)實(shí)例中直接將排序函數(shù)的實(shí)現(xiàn)寫(xiě)在應(yīng)該傳遞函數(shù)的位置,省去了定義排序函數(shù)的過(guò)程,對(duì)于這種不需要復(fù)用,且短小的函數(shù),直接傳遞函數(shù)體可以增加代碼的可讀性。

Lambda表達(dá)式語(yǔ)法定義

  1. 捕獲列表。在C++規(guī)范中也稱(chēng)為L(zhǎng)ambda導(dǎo)入器, 捕獲列表總是出現(xiàn)在Lambda函數(shù)的開(kāi)始處。實(shí)際上,[]是Lambda引出符。編譯器根據(jù)該引出符判斷接下來(lái)的代碼是否是Lambda函數(shù),捕獲列表能夠捕捉上下文中的變量以供Lambda函數(shù)使用。
  2. 參數(shù)列表。與普通函數(shù)的參數(shù)列表一致。如果不需要參數(shù)傳遞,則可以連同括號(hào)“()”一起省略。
  3. 可變規(guī)格。mutable修飾符, 默認(rèn)情況下Lambda函數(shù)總是一個(gè)const函數(shù),mutable可以取消其常量性。在使用該修飾符時(shí),參數(shù)列表不可省略(即使參數(shù)為空)。
  4. 異常說(shuō)明。用于Lamdba表達(dá)式內(nèi)部函數(shù)拋出異常。
  5. 返回類(lèi)型。 追蹤返回類(lèi)型形式聲明函數(shù)的返回類(lèi)型。我們可以在不需要返回值的時(shí)候也可以連同符號(hào)”->”一起省略。此外,在返回類(lèi)型明確的情況下,也可以省略該部分,讓編譯器對(duì)返回類(lèi)型進(jìn)行推導(dǎo)。
  6. lambda函數(shù)體。內(nèi)容與普通函數(shù)一樣,不過(guò)除了可以使用參數(shù)之外,還可以使用所有捕獲的變量。

Lambda表達(dá)式參數(shù)詳解

Lambda捕獲列表

Lambda表達(dá)式與普通函數(shù)最大的區(qū)別是,除了可以使用參數(shù)以外,Lambda函數(shù)還可以通過(guò)捕獲列表訪(fǎng)問(wèn)一些上下文中的數(shù)據(jù)。具體地,捕捉列表描述了上下文中哪些數(shù)據(jù)可以被Lambda使用,以及使用方式(以值傳遞的方式或引用傳遞的方式)。語(yǔ)法上,在“[]”包括起來(lái)的是捕獲列表,捕獲列表由多個(gè)捕獲項(xiàng)組成,并以逗號(hào)分隔。捕獲列表有以下幾種形式:

  • []表示不捕獲任何變量
auto function = ([]{
		std::cout << "Hello World!" << std::endl;
	}
);

function();
  • [var]表示值傳遞方式捕獲變量var
int num = 100;
auto function = ([num]{
		std::cout << num << std::endl;
	}
);

function();
  • [=]表示值傳遞方式捕獲所有父作用域的變量(包括this
int index = 1;
int num = 100;
auto function = ([=]{
			std::cout << "index: "<< index << ", " 
                << "num: "<< num << std::endl;
	}
);

function();
  • [&var]表示引用傳遞捕捉變量var
int num = 100;
auto function = ([&num]{
		num = 1000;
		std::cout << "num: " << num << std::endl;
	}
);

function();
  • [&]表示引用傳遞方式捕捉所有父作用域的變量(包括this
int index = 1;
int num = 100;
auto function = ([&]{
		num = 1000;
		index = 2;
		std::cout << "index: "<< index << ", " 
            << "num: "<< num << std::endl;
	}
);

function();
  • [this]表示值傳遞方式捕捉當(dāng)前的this指針
#include <iostream>
using namespace std;
 
class Lambda
{
public:
    void sayHello() {
        std::cout << "Hello" << std::endl;
    };

    void lambda() {
        auto function = [this]{ 
            this->sayHello(); 
        };

        function();
    }
};
 
int main()
{
    Lambda demo;
    demo.lambda();
}
  • [=, &] 拷貝與引用混合
    • [=, &a, &b]表示以引用傳遞的方式捕捉變量ab,以值傳遞方式捕捉其它所有變量。
int index = 1;
int num = 100;
auto function = ([=, &index, &num]{
		num = 1000;
		index = 2;
		std::cout << "index: "<< index << ", " 
            << "num: "<< num << std::endl;
	}
);

function();
  • [&, a, this]表示以值傳遞的方式捕捉變量athis,引用傳遞方式捕捉其它所有變量。

不過(guò)值得注意的是,捕捉列表不允許變量重復(fù)傳遞。下面一些例子就是典型的重復(fù),會(huì)導(dǎo)致編譯時(shí)期的錯(cuò)誤。例如:

  • [=,a]這里已經(jīng)以值傳遞方式捕捉了所有變量,但是重復(fù)捕捉a了,會(huì)報(bào)錯(cuò)的;
  • [&,&this]這里&已經(jīng)以引用傳遞方式捕捉了所有變量,再捕捉this也是一種重復(fù)。

如果Lambda主體total通過(guò)引用訪(fǎng)問(wèn)外部變量,并factor通過(guò)值訪(fǎng)問(wèn)外部變量,則以下捕獲子句是等效的:

[&total, factor]
[factor, &total]
[&, factor]
[factor, &]
[=, &total]
[&total, =]

Lambda參數(shù)列表

除了捕獲列表之外,Lambda還可以接受輸入?yún)?shù)。參數(shù)列表是可選的,并且在大多數(shù)方面類(lèi)似于函數(shù)的參數(shù)列表。

auto function = [] (int first, int second){
    return first + second;
};
	
function(100, 200);

可變規(guī)格mutable

mutable修飾符, 默認(rèn)情況下Lambda函數(shù)總是一個(gè)const函數(shù),mutable可以取消其常量性。在使用該修飾符時(shí),參數(shù)列表不可省略(即使參數(shù)為空)。

#include <iostream>
using namespace std;

int main()
{
   int m = 0;
   int n = 0;
   [&, n] (int a) mutable { m = ++n + a; }(4);
   cout << m << endl << n << endl;
}

異常說(shuō)明

你可以使用 throw() 異常規(guī)范來(lái)指示 Lambda 表達(dá)式不會(huì)引發(fā)任何異常。與普通函數(shù)一樣,如果 Lambda 表達(dá)式聲明 C4297 異常規(guī)范且 Lambda 體引發(fā)異常,Visual C++ 編譯器將生成警告 throw() 。

int main() // C4297 expected 
{ 
 	[]() throw() { throw 5; }(); 
}

在MSDN的異常規(guī)范中,明確指出異常規(guī)范是在 C++11 中棄用的 C++ 語(yǔ)言功能。因此這里不建議不建議大家使用。

返回類(lèi)型

Lambda表達(dá)式的返回類(lèi)型會(huì)自動(dòng)推導(dǎo)。除非你指定了返回類(lèi)型,否則不必使用關(guān)鍵字。返回型類(lèi)似于通常的方法或函數(shù)的返回型部分。但是,返回類(lèi)型必須在參數(shù)列表之后,并且必須在返回類(lèi)型->之前包含類(lèi)型關(guān)鍵字。如果Lambda主體僅包含一個(gè)return語(yǔ)句或該表達(dá)式未返回值,則可以省略L(fǎng)ambda表達(dá)式的return-type部分。如果Lambda主體包含一個(gè)return語(yǔ)句,則編譯器將從return表達(dá)式的類(lèi)型中推斷出return類(lèi)型。否則,編譯器將返回類(lèi)型推導(dǎo)為void。

auto x1 = [](int i){ return i; };

Lambda函數(shù)體

Lambda表達(dá)式的Lambda主體(標(biāo)準(zhǔn)語(yǔ)法中的復(fù)合語(yǔ)句)可以包含普通方法或函數(shù)的主體可以包含的任何內(nèi)容。普通函數(shù)和Lambda表達(dá)式的主體都可以訪(fǎng)問(wèn)以下類(lèi)型的變量:

  • 捕獲變量
  • 形參變量
  • 局部聲明的變量
  • 類(lèi)數(shù)據(jù)成員,當(dāng)在類(lèi)內(nèi)聲明this并被捕獲時(shí)
  • 具有靜態(tài)存儲(chǔ)持續(xù)時(shí)間的任何變量,例如全局變量
#include <iostream>
using namespace std;

int main()
{
   int m = 0;
   int n = 0;
   [&, n] (int a) mutable { m = ++n + a; }(4);
   cout << m << endl << n << endl;
}

Lambda表達(dá)式的優(yōu)缺點(diǎn)

Lambda表達(dá)式的優(yōu)點(diǎn)

  • 可以直接在需要調(diào)用函數(shù)的位置定義短小精悍的函數(shù),而不需要預(yù)先定義好函數(shù)
std::find_if(v.begin(), v.end(), [](int& item){return item > 2});
  • 使用Lamdba表達(dá)式變得更加緊湊,結(jié)構(gòu)層次更加明顯、代碼可讀性更好

Lambda表達(dá)式的缺點(diǎn)

  • Lamdba表達(dá)式語(yǔ)法比較靈活,增加了閱讀代碼的難度
  • 對(duì)于函數(shù)復(fù)用無(wú)能為力

Lambda表達(dá)式工作原理

Lambda表達(dá)式工作原理

編譯器會(huì)把一個(gè)Lambda表達(dá)式生成一個(gè)匿名類(lèi)的匿名對(duì)象,并在類(lèi)中重載函數(shù)調(diào)用運(yùn)算符,實(shí)現(xiàn)了一個(gè)operator()方法。

auto print = []{cout << "Hello World!" << endl; };

編譯器會(huì)把上面這一句翻譯為下面的代碼:

class print_class
{
public:
	void operator()(void) const
	{
		cout << "Hello World!" << endl;
	}
};
// 用構(gòu)造的類(lèi)創(chuàng)建對(duì)象,print此時(shí)就是一個(gè)函數(shù)對(duì)象
auto print = print_class();

C++仿函數(shù)

仿函數(shù)(functor)又稱(chēng)為函數(shù)對(duì)象(function object)是一個(gè)能行使函數(shù)功能的類(lèi)。仿函數(shù)的語(yǔ)法幾乎和我們普通的函數(shù)調(diào)用一樣,不過(guò)作為仿函數(shù)的類(lèi),都必須重載operator()運(yùn)算符,仿函數(shù)與Lamdba表達(dá)式的作用是一致的。舉個(gè)例子:

#include <iostream>
#include <string>
using namespace std;
 
class Functor
{
public:
    void operator() (const string& str) const
    {
        cout << str << endl;
    }
};
 
int main()
{
    Functor myFunctor;
    myFunctor("Hello world!");
    return 0;
}

Lamdba表達(dá)式適用場(chǎng)景

Lamdba表達(dá)式應(yīng)用于STL算法庫(kù)

for_each應(yīng)用實(shí)例

int a[4] = {11, 2, 33, 4};
sort(a, a+4, [=](int x, int y) -> bool { return x%10 < y%10; } );
for_each(a, a+4, [=](int x) { cout << x << " ";} );

find_if應(yīng)用實(shí)例

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;
});

remove_if應(yīng)用實(shí)例

std::vector<int> vec_data = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int x = 5;
vec_data.erase(std::remove_if(vec.date.begin(), vec_data.end(), [](int i) { 
    return n < x;}), vec_data.end());

std::for_each(vec.date.begin(), vec_data.end(), [](int i) { 
    std::cout << i << std::endl;});

短小不需要復(fù)用函數(shù)場(chǎng)景

sort函數(shù)

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main(void)
{
    int data[6] = { 3, 4, 12, 2, 1, 6 };
    vector<int> testdata;
    testdata.insert(testdata.begin(), data, data + 6);

    // 對(duì)于比較大小的邏輯,使用lamdba不需要在重新定義一個(gè)函數(shù)
    sort(testdata.begin(), testdata.end(), [](int a, int b){ 
        return a > b; });

    return 0;
}

Lamdba表達(dá)式應(yīng)用于多線(xiàn)程場(chǎng)景

#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>

int main()
{
    // vector 容器存儲(chǔ)線(xiàn)程
    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";

    // 通過(guò) for_each 循環(huán)每一個(gè)線(xiàn)程
    // 第三個(gè)參數(shù)賦值一個(gè)task任務(wù)
    // 符號(hào)'[]'會(huì)告訴編譯器我們正在用一個(gè)匿名函數(shù)
    // lambda函數(shù)將它的參數(shù)作為線(xiàn)程的引用t
    // 然后一個(gè)一個(gè)的join
    std::for_each(workers.begin(), workers.end(), [](std::thread &t;) 
    {
        t.join();
    });

    return 0;
}
std::mutex mutex;
std::condition_variable condition;
std::queue<std::string> queue_data;

std::thread threadBody([&]{
	std::unique_lock<std::mutex> lock_log(mutex);
	condition.wait(lock_log, [&]{
		return !queue_data.front();
	});
	std::cout << "queue data: " << queue_data.front();
	lock_log.unlock();
});

queue_data.push("this is my data");
condition.notity_one();

if(threadBody.joinable())
{
	threadBody.join();
}

Lamdba表達(dá)式應(yīng)用于函數(shù)指針與function

#include <iostream>
#include <functional>
using namespace std;

int main(void)
{
    int x = 8, y = 9;
    auto add = [](int a, int b) { return a + b; };
    std::function<int(int, int)> Add = [=](int a, int b) { return a + b; };

    cout << "add: " << add(x, y) << endl;
    cout << "Add: " << Add(x, y) << endl;

    return 0;
}

Lamdba表達(dá)式作為函數(shù)的入?yún)?/h2>
using FuncCallback = std::function<void(void)>;

void DataCallback(FuncCallback callback)
{
	std::cout << "Start FuncCallback!" << std::endl;
	callback();
	std::cout << "End FuncCallback!" << std::endl;
}

auto callback_handler = [&](){
	std::cout << "This is callback_handler";
};

DataCallback(callback_handler);

Lamdba表達(dá)式在QT中的應(yīng)用

QTimer *timer=new QTimer;
timer->start(1000);
QObject::connect(timer, &QTimer::timeout, [&](){
        qDebug() << "Lambda表達(dá)式";
});
int a = 10;
QString str1 = "漢字博大精深";
connect(pBtn4, &QPushButton::clicked, [=](bool checked){
	qDebug() << a <<str1;
	qDebug() << checked;
	qDebug() << "Hua Windows Lambda Button";
});

總結(jié)

對(duì)于Lambda這種新東西,有的人用的非常爽,而有的人看著都不爽。仁者見(jiàn)仁,智者見(jiàn)智。不管怎么樣,學(xué)了總不會(huì)錯(cuò)!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多