120 lines
3.4 KiB
Markdown
120 lines
3.4 KiB
Markdown
---
|
||
tags:
|
||
aliases:
|
||
date: 2022-06-12
|
||
time: 18:21:42
|
||
description:
|
||
---
|
||
|
||
一個簡單的 Lamdba 運算式:
|
||
```cpp
|
||
[] (int x, int y) -> bool {
|
||
return x < y;
|
||
}
|
||
```
|
||
|
||
- 以中括號開頭,中括號被稱為*lamdba 導入器(lamdba introducer)*
|
||
- 小括號裡面是*lamdba 參數列表(lambda parameter list)*
|
||
- 如果沒有參數,小括號可以省略,`[] () {...}` 可以簡寫成 `[] {...}`
|
||
- 箭號(`->`)後面是回傳的型別,如果沒寫就由 `return` 自動推斷
|
||
|
||
將 Lamdba 運算式指定給變數:
|
||
```cpp
|
||
auto comapre = [] (int x, int y) -> bool {
|
||
return x < y;
|
||
};
|
||
```
|
||
|
||
## Lamdba的擷取子句
|
||
以中括號開頭的 *lamdba 導入器*可以將外部的變數傳給 Lamdba 運算式,正式名稱是「擷取子句(capture clause)」。
|
||
`[=]` 表示它們會以值擷取(captured by value)。Scope內的變數可以在 lamdba 內使用,但是不可以改變。
|
||
`[&]` 表示它們會以址擷取(captured by reference)。Scope內的變數可以在 lamdba 內使用,可以改變。
|
||
|
||
### 以值擷取(captured by value)
|
||
假設有一段程式如下:
|
||
```cpp
|
||
void testLambda() {
|
||
float notUsed = 1.0f;
|
||
std::vector<int32_t> numlist{10, 20, 30, 50, 60};
|
||
auto findInRange = [=](int32_t start, int32_t end) {
|
||
for (auto num : numlist) {
|
||
if (num >= start && num <= end) return true;
|
||
}
|
||
return false;
|
||
};
|
||
|
||
std::cout << "Result: " << findInRange(25, 35) << "\n";
|
||
}
|
||
```
|
||
|
||
用`[=]`可以用來擷取 lamdba scope範圍所及的變數,沒有在 Lamdba 運算式裡面被用到的變數就不會被擷取,例如 `float notUsed = 1.0f;`。
|
||
另一個重點是:**被擷取的變數是不可以更改的**。例如,不能在lamdba裡面這樣寫:
|
||
```cpp
|
||
auto findInRange = [=](int32_t start, int32_t end) {
|
||
numlist.push_back(5); // ERROR!
|
||
|
||
for (auto num : numlist) {
|
||
if (num >= start && num <= end) return true;
|
||
}
|
||
return false;
|
||
};
|
||
```
|
||
|
||
如果一定要在 lambda內改變擷取的變數,那必須指名 lambda 為 `mutable`:
|
||
```cpp
|
||
auto findInRange = [=](int32_t start, int32_t end) mutable { // <-- assign mutable
|
||
numlist.push_back(5);
|
||
|
||
for (auto num : numlist) {
|
||
if (num >= start && num <= end) return true;
|
||
}
|
||
return false;
|
||
};
|
||
```
|
||
|
||
根據書上解釋 ,可以裡解為 compiler 會將 lamdba 編為一個 class,像是:
|
||
```cpp
|
||
class __Lambda8C1A5 {
|
||
public:
|
||
__Lambda8C1A5(const std::vector<int32_t>& arg1) : numlist(arg1) {}
|
||
auto operator()(int32_t start, int32_t end) const { // const!
|
||
for (auto num : numlist) {
|
||
if (num >= start && num <= end) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
private:
|
||
std::vector<int32_t> numlist;
|
||
};
|
||
```
|
||
|
||
這也解釋了 lamdba 的擷取範圍與原理。而 `mutable` 則是讓 `operator()` 不為 `const`,如下:
|
||
```cpp
|
||
auto findInRange = [=](int32_t start, int32_t end) mutable { // <-- assign mutable
|
||
numlist.push_back(5);
|
||
|
||
for (auto num : numlist) {
|
||
if (num >= start && num <= end) return true;
|
||
}
|
||
return false;
|
||
};
|
||
|
||
...
|
||
|
||
class __Lambda8C1A5 {
|
||
public:
|
||
__Lambda8C1A5(const std::vector<int32_t>& arg1) : numlist(arg1) {}
|
||
auto operator()(int32_t start, int32_t end) { // No const here
|
||
for (auto num : numlist) {
|
||
if (num >= start && num <= end) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
private:
|
||
std::vector<int32_t> numlist;
|
||
};
|
||
```
|
||
|
||
### 以址擷取(captured by reference) |