亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

什么是C ++ 11中的lambda表達式?

什么是C ++ 11中的lambda表達式?

C++
撒科打諢 2019-05-24 15:46:28
什么是C ++ 11中的lambda表達式?什么是C ++ 11中的lambda表達式?我什么時候用?他們解決了哪些問題在引入之前是不可能的?一些示例和用例將是有用的。
查看完整描述

4 回答

?
紅顏莎娜

TA貢獻1842條經驗 獲得超13個贊

問題

C ++包含有用的通用函數,例如std::for_eachstd::transform,它們非常方便。不幸的是,他們也可以是相當繁瑣的使用,特別是如果函子,你想申請是唯一的特定功能。

#include <algorithm>#include <vector>namespace {
  struct f {
    void operator()(int) {
      // do something
    }
  };}void func(std::vector<int>& v) {
  f f;
  std::for_each(v.begin(), v.end(), f);}

如果你只使用f一次并且在那個特定的地方,那么寫一個全班只是為了做一些微不足道的事情似乎有點過分了。

在C ++ 03中,您可能想要編寫類似下面的內容,以保持函數本地:

void func2(std::vector<int>& v) {
  struct {
    void operator()(int) {
       // do something
    }
  } f;
  std::for_each(v.begin(), v.end(), f);}

但是這是不允許的,f不能傳遞給C ++ 03中的模板函數。

新的解決方案

C ++ 11引入了lambdas,允許你編寫一個內聯的匿名函子來替換struct f。對于小的簡單示例,這可以更清晰地閱讀(它將所有內容保存在一個地方)并且可能更簡單地維護,例如以最簡單的形式:

void func3(std::vector<int>& v) {
  std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });}

Lambda函數只是匿名函子的語法糖。

返回類型

在簡單的情況下,lambda的返回類型是為您推導出來的,例如:

void func4(std::vector<double>& v) {
  std::transform(v.begin(), v.end(), v.begin(),
                 [](double d) { return d < 0.00001 ? 0 : d; }
                 );}

但是當你開始編寫更復雜的lambda時,很快就會遇到編譯器無法推斷出返回類型的情況,例如:

void func4(std::vector<double>& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });}

要解決此問題,您可以使用以下方法顯式指定lambda函數的返回類型-> T

void func4(std::vector<double>& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) -> double {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });}

“捕獲”變量

到目前為止,我們還沒有使用除了傳遞給lambda之外的任何東西,但我們也可以在lambda中使用其他變量。如果要訪問其他變量,可以使用capture子句([]表達式),這些子句在這些示例中尚未使用,例如:

void func5(std::vector<double>& v, const double& epsilon) {
    std::transform(v.begin(), v.end(), v.begin(),
        [epsilon](double d) -> double {
            if (d < epsilon) {
                return 0;
            } else {
                return d;
            }
        });}

您可以通過引用和值捕獲,您可以分別使用&和指定=

  • [&epsilon] 通過引用捕獲

  • [&] 通過引用捕獲lambda中使用的所有變量

  • [=] 按值捕獲lambda中使用的所有變量

  • [&, epsilon] 捕獲變量,如[&],但epsilon值

  • [=, &epsilon] 捕獲變量,如[=],但epsilon通過引用

默認情況下生成的operator()const隱式,默認情況下,const當您訪問它們時捕獲將是。這具有以下效果:具有相同輸入的每個調用將產生相同的結果,但是您可以將lambda標記為mutable請求operator()生成的不是const。


查看完整回答
反對 回復 2019-05-24
?
一只萌萌小番薯

TA貢獻1795條經驗 獲得超7個贊

Lambda表達式通常用于封裝算法,以便將它們傳遞給另一個函數。但是,可以在定義時立即執行lambda

[&](){ ...your code... }(); // immediately executed lambda expression

在功能上等同于

{ ...your code... } // simple code block

這使得lambda表達式成為重構復雜函數的強大工具。首先將代碼段包裝在lambda函數中,如上所示。然后可以在每個步驟之后通過中間測試逐漸執行顯式參數化的過程。一旦您完全參數化了代碼塊(如刪除所示&),您可以將代碼移動到外部位置并使其成為正常功能。

同樣,您可以使用lambda表達式根據算法的結果初始化變量 ...

int a = []( int b ){ int r=1; while (b>0) r*=b--; return r; }(5); // 5!

作為一種分區程序邏輯的方法,您甚至可能會發現將lambda表達式作為參數傳遞給另一個lambda表達式很有用......

[&]( std::function<void()> algorithm ) // wrapper section
   {
   ...your wrapper code...
   algorithm();
   ...your wrapper code...
   }([&]() // algorithm section
   {
   ...your algorithm code...
   });

Lambda表達式還允許您創建命名嵌套函數,這可以是避免重復邏輯的便捷方法。當將非平凡函數作為參數傳遞給另一個函數時,使用命名的lambdas在眼睛上也會更容易(與匿名內聯lambda相比)。 注意:關閉大括號后不要忘記分號。

auto algorithm = [&]( double x, double m, double b ) -> double
   {
   return m*x+b;
   };int a=algorithm(1,2,3), b=algorithm(4,5,6);

如果后續分析顯示函數對象的顯著初始化開銷,您可以選擇將其重寫為普通函數。


查看完整回答
反對 回復 2019-05-24
?
互換的青春

TA貢獻1797條經驗 獲得超6個贊

答案

問:C ++ 11中的lambda表達式是什么?

答:在引擎蓋下,它是一個帶有重載operator()const的自動生成類的對象。這種對象稱為閉包,由編譯器創建。這個'閉包'概念接近于C ++ 11中的綁定概念。但是lambdas通常會生成更好的代碼。通過閉包調用允許完全內聯。

問:我什么時候使用?

答:定義“簡單和小邏輯”并要求編譯器執行上一個問題的生成。你給編譯器一些你想要在operator()中的表達式。編譯器將為您生成所有其他東西。

問:他們解決了哪些問題在引入之前是不可能的?

答:這是某種語法糖,比如運算符重載而不是自定義添加,子作用操作的函數......但它保存了更多不需要的代碼行,將1-3行真實邏輯包裝到某些類等等!一些工程師認為,如果線的數量較少,那么在其中產生錯誤的機會就會減少(我也這么認為)

用法示例

auto x = [=](int arg1){printf("%i", arg1); };void(*f)(int) = x;f(1);x(1);

關于lambdas的額外內容,未提及問題。如果您不感興趣,請忽略此部分

1.捕獲的價值。你可以捕獲什么

1.1。您可以在lambdas中引用具有靜態存儲持續時間的變量。他們都被抓獲了。

1.2。您可以使用lambda“按值”捕獲值。在這種情況下,捕獲的變量將被復制到函數對象(閉包)。

[captureVar1,captureVar2](int arg1){}

1.3。你可以捕獲參考。& - 在這種情況下意味著參考,而不是指針。

   [&captureVar1,&captureVar2](int arg1){}

1.4。它存在通過值或引用捕獲所有非靜態變量的符號

  [=](int arg1){} // capture all not-static vars by value

  [&](int arg1){} // capture all not-static vars by reference

1.5。它存在通過值或通過引用捕獲所有非靜態變量并指定smth的表示法。更多。示例:按值捕獲所有非靜態變量,但通過引用捕獲Param2

[=,&Param2](int arg1){}

通過引用捕獲所有非靜態變量,但通過值捕獲Param2

[&,Param2](int arg1){}

2.退貨類型扣除

2.1。如果lambda是一個表達式,則可以推導出Lambda返回類型?;蛘吣梢悦鞔_指定它。

[=](int arg1)->trailing_return_type{return trailing_return_type();}

如果lambda有多個表達式,則必須通過尾隨返回類型指定返回類型。此外,類似的語法可以應用于自動函數和成員函數

3.捕獲的值。什么你無法捕捉

3.1。您只能捕獲本地變量,而不能捕獲對象的成員變量。

4.Сonversions

4.1 !! Lambda不是函數指針,它不是匿名函數,但可以將無捕獲的 lambdas隱式轉換為函數指針。

PS

  1. 有關lambda語法信息的更多信息,請參閱編程語言C ++#337,2012-01-16,5.1.2的工作草案。Lambda表達式,第88頁

  2. 在C ++ 14中,添加了名為“init capture”的額外功能。它允許對閉包數據成員進行仲裁聲明:

auto toFloat = [](int value) { return float(value);};

auto interpolate = [min = toFloat(0), max = toFloat(255)](int value)->float { return (value - min) / (max - min);};


查看完整回答
反對 回復 2019-05-24
  • 4 回答
  • 0 關注
  • 1362 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號