1. 程式人生 > >C++ lambda函式說明

C++ lambda函式說明

Lambda函式(C++11起)

C++

C++語言

構造一個閉包:能在作用域內捕獲變數一個的匿名函式物件。

語法

[ capture ] ( params ) mutable exception attribute -> ret { body } (1)
[ capture ] ( params ) -> ret { body } (2)
[ capture ] ( params ) { body } (3)
[ capture ] { body } (4)

1) 完整的宣告

2) 一個常lambda的宣告:按副本捕獲的物件不能被修改。

3) 省略字尾返回值型別:閉包的operator()的返回值型別是根據以下規則推匯出的:

  • 如果body僅包含單一的return語句,那麼返回值型別是返回表示式的型別(在此隱式轉換之後的型別:右值到左值、陣列與指標、函式到指標)
  • 否則,返回型別是void

4) 省略引數列表:函式沒有引數,即引數列表是()

解釋

mutable - 允許body修改傳值進來的形參,以及呼叫它們的非常成員函式。
exception - 提供閉包型別的operator()成員函式的異常說明noexcept語句
attribute - 提供閉包型別的operator()成員函式的
屬性說明
capture - 指定哪些在函式宣告處的作用域中可見的符號將在函式體內可見。

符號表可按如下規則傳入:

  • [a,&b],按值捕獲a,並按引用捕獲b
  • [this],按值捕獲了this指標
  • [&] 按引用捕獲在lambda表示式所在函式的函式體中提及的全部自動儲存持續性變數
  • [=] 按值捕獲在lambda表示式所在函式的函式體中提及的全部自動儲存持續性變數
  • [] 什麼也沒有捕獲
params - 引數列表,與命名函式一樣
ret - 返回值型別。如果不存在,它由該函式的return語句來隱式決定(或者是void,例如當它不返回任何值的時候)
body - 函式體

Lambda表示式構造唯一的匿名的非聯合體非聚合體的匿名臨時物件,叫做閉包型(ClosureType)。它有如下成員:

ClosureType::

operator()(params)

ret operator()(params) const { body }

(關鍵字mutable沒被使用)

ret operator()(params) { body }

(關鍵字mutable被使用)

Executes the body of the lambda-expression, when invoked. When accessing a variable, accesses its captured copy (for the entities captured by copy), or the original object (for the entities captured by reference). Unless the keyword mutable was used in the lamda-expression, the objects that were captured by copy are non-modifiable from inside this operator().

Dangling references

If an entity is captured by reference, implicitly or explicitly, and the function call operator of the closure object is invoked after the entity's lifetime has ended, undefined behavior occurs. The C++ closures do not extend the lifetimes of the captured references.

ClosureType::

operator ret(*)(params)()

typedef ret(*F)(params); operator F() const;

This member function is only defined if the capture list of the lambda-expression is empty.

The value returned by this conversion function is a function pointer that, when invoked, has the same effect as invoking the closure object's function call operator directly.

ClosureType::

ClosureType()

ClosureType() = delete;

ClosureType(const ClosureType& ) = default;

ClosureType(ClosureType&& ) = default;

Closure types are not DefaultConstructible. The copy constructor and the move constructor are implicitly-declared and may be implicitly-defined according to the usual rules for implicit 拷貝建構函式 and 移動的建構函式.

ClosureType::

operator=()

ClosureType& operator=(const ClosureType&) = delete;

Closure types are not CopyAssignable.

ClosureType::

~ClosureType()

~ClosureType() = default;

The destructor is implicitly-declared.

ClosureType::

CapturedParam

T1 a;

T2 b;

...

If the lambda-expression captures anything by copy (either implicitly with capture clause [=] or explicitly with a capture that does not include the character &, e.g. [a, b, c]), the closure type includes unnamed non-static data members, declared in unspecified order, that hold copies of all entities that were so captured.

The type of each data member is the type of the corresponding captured entity, except if the entity has reference type (in that case, references to functions are captured as-is, and references to objects are captured as copies of the referenced objects).

For the entities that are captured by reference (with the default capture [&] or when using the character &, e.g.[&a, &b, &c]), it is unspecified if additional data members are declared in the closure type.

本章尚未完成 原因:scope rules, capture list rules, nested lambdas, implicit capture vs odr use, decltype

例子

這個例子展示了(a)如何把一個lambda表示式放在通用的演算法中,以及(b)lambda表示式得到的物件如何儲存在std::function物件中。 

#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
 
int main()
{
    std::vector<int> c { 1,2,3,4,5,6,7 };
    int x = 5;
    c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; } ), c.end());
 
    std::cout << "c: ";
    for (auto i: c) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
 
    std::function<int (int)> func = [](int i) { return i+4; };
    std::cout << "func: " << func(6) << '\n'; 
}
#include <iostream>
#include <algorithm>
#include <functional>
 
int main()
{
    std::vector<int> c { 1,2,3,4,5,6,7 };
    int x = 5;
    c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; } ), c.end());
 
    std::cout << "c: ";
    for (auto i: c) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
 
    std::function<int (int)> func = [](int i) { return i+4; };
    std::cout << "func: " << func(6) << '\n'; 
}

輸出:

c: 5 6 7
func: 10

另請參閱

表達一個由表示式定義的一個型別(C++11)[edit]
包裝帶有指定的函式呼叫簽名的任何型別的可呼叫物件   (類模板)