# ラムダ式のキャプチャ
C++ではラムダ式で関数オブジェクトを定義することができる。
```cpp=
auto func = std::bind([](int a, double b) {
return a + b;
}, 1);
```
戻り値の型は明記されていないが推論で定まっている。
()の中には引数が指定でき、その引数に前から順に値を束縛することができる。
std::function, std::bindを使用できる。
一方`[]`の方が使用されていることは少ない。これについて。
## Capture
ラムダ式の中では基本そのスコープの中で生きている値にしかアクセスできない。
しかしキャプチャという機能を使うと外側の変数も使用できる。
以下のように変数を指定して参照を渡せる。
```cpp=
int a = 1;
auto func = [&a](dougble b) {
return a + b;
});
```
日本語ではラムダ導入子というらしい。
参照でなくコピーすることもできる。以下が書き方の例。
```cpp=
[&]: その環境にある変数をすべて参照できる
[=]: その環境にあるすべての変数をコピーして使える
[&x]: 変数xのみ参照
[x]: 変数xのみコピー
[=, &x]: 変数xのみ参照、ほかはコピー
```
## Chromiumでの関数オブジェクト
Chromiumでは標準ライブラリの関数オブジェクト関連はbanned。
[std::bind](https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/c++-features.md#std_bind-banned), [std::function}https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/c++-features.md#std_function-banned](https://chromium.googlesource.com/chromium/src/+/main/styleguide/c++/c++-features.md#std_function-banned) はいずれもbannedだが、これは関数オブジェクトというコンセプトを使うなということではなく、Chromiumの自前実装であるbase::Bindやbase::OnceClosureを使おうということ。
base::Bind は std::bind に比べてライフタイム問題で安全。
base::Bindではキャプチャを(テスト以外では)禁止しておりまた生ポインタを[base::Unretained](https://source.chromium.org/chromium/chromium/src/+/main:base/functional/bind.h;l=169;drc=e5fb8148967b396b9f566843cba51516bd5950a8)で宣言するようガードがかかる。
[ここ](https://source.chromium.org/chromium/chromium/src/+/main:base/functional/bind_internal.h;l=131;drc=e5fb8148967b396b9f566843cba51516bd5950a8)でチェックされている。
### BindLambdaForTesting
[base::BindLambdaForTesting](https://source.chromium.org/chromium/chromium/src/+/main:base/test/bind.h;l=52;drc=e5fb8148967b396b9f566843cba51516bd5950a8) で作ったコールバックは、キャプチャ禁止の制約を受けない。
```cpp=
template <typename Lambda,
std::enable_if_t<internal::HasConstCallOperator<Lambda>>* = nullptr>
decltype(auto) BindLambdaForTesting(Lambda&& lambda) {
using Signature = internal::ExtractCallableRunType<std::decay_t<Lambda>>;
// If WTF::BindRepeating is available, and a callback argument is in WTF, then
// this call is ambiguous without the full namespace path.
return ::base::BindRepeating(
&internal::BindLambdaHelper<Lambda, Signature>::Run,
std::forward<Lambda>(lambda));
}
```
ExtractCallableRunType は関数オブジェクトの型を計算している。最初の例の場合 `double(int, double)`
## Note
[concepts](https://cpprefjp.github.io/lang/cpp20/concepts.html)を発見した。
```cpp=
template <typename Functor>
requires(IsCallableObject<Functor>::value)
struct FunctorTraits<Functor> {
using RunType = ExtractCallableRunType<Functor>;
static constexpr bool is_method = false;
static constexpr bool is_nullable = false;
static constexpr bool is_callback = false;
static constexpr bool is_stateless = std::is_empty_v<Functor>;
template <typename RunFunctor, typename... RunArgs>
static ExtractReturnType<RunType> Invoke(RunFunctor&& functor,
RunArgs&&... args) {
return std::forward<RunFunctor>(functor)(std::forward<RunArgs>(args)...);
}
};
```
requires節でマッチするケースに制約をかけている。
この場合`IsCallabkeObject<Functor>`にvalueがtrueなケースのみマッチするような書き方。
```cpp=
template <typename Functor>
struct IsCallableObject : std::false_type {};
template <typename Callable>
requires requires { &Callable::operator(); }
struct IsCallableObject<Callable> : std::true_type {};
```
IsCallableObjectは operator() があるFunctorを選別している。