# base::OwnedRef
[base::OwnedRef](https://source.chromium.org/chromium/chromium/src/+/main:base/functional/bind.h;l=357;drc=7824b6f569e030d369cb58ba731b9c56eaeb6d93)とはChromiumの中でmutableなオブジェクトをcallbackに束縛したいときに使われるヘルパー関数。
適当に使ってたら詰まったので確認してみる。
## 概要
```cpp
void foo(int& arg) { std::cout << ++arg << std::endl; }
int counter = 0;
RepeatingClosure foo_callback = BindRepeating(&foo, OwnedRef(counter));
foo_callback.Run(); // 1
foo_callback.Run(); // 2
foo_callback.Run(); // 3
std::cout << counter << std::endl; // 0
```
実行例からわかるように、base::OwnedRefはコピーを作っていることに注意。
元の変数の方の値はcallbackによって変わっていない。
実装を見てみる。
```cpp
template <typename T>
internal::OwnedRefWrapper<std::decay_t<T>> OwnedRef(T&& t) {
return internal::OwnedRefWrapper<std::decay_t<T>>(std::forward<T>(t));
}
template <typename T>
class OwnedRefWrapper {
public:
explicit OwnedRefWrapper(const T& t) : t_(t) {}
explicit OwnedRefWrapper(T&& t) : t_(std::move(t)) {}
T& get() const { return t_; }
private:
mutable T t_;
};
```
const参照を受け取ってmutableとして保存する。
ちなみにdecay_tは推論された型を取るやつ。例えば`char[]`を渡すと`char*`に変身する。
Bindで渡されるArg型はいくつかの条件を満たしていないといけない。
条件は[ParamCanBeBound](https://source.chromium.org/chromium/chromium/src/+/main:base/functional/bind_internal.h;l=1444;drc=f4a00cc248dd2dc8ec8759fb51620d47b5114090)の中の[`value`](https://source.chromium.org/chromium/chromium/src/+/main:base/functional/bind_internal.h;l=1577-1585;drc=f4a00cc248dd2dc8ec8759fb51620d47b5114090)として計算される。
例えば以下はForwardできるかを確認している。
```cpp!
template <bool v = UnwrappedParam::kCanBeForwardedToBoundFunctor ||
!UnwrappedParam::kIsUnwrappedForwardableNonConstReference>
struct NonConstRefParamMustBeWrapped { ... }
// kIsUnwrappedForwardableNonConstReferenceの実体
static constexpr bool kIsUnwrappedForwardableNonConstReference =
std::is_lvalue_reference_v<FunctorParamType> &&
!std::is_const_v<std::remove_reference_t<FunctorParamType>> &&
std::is_convertible_v<std::decay_t<ForwardingType>&,
FunctorParamType>;
```
const referenceならOKで、そうでないならwrapしていないといけないので、unwrapかつnon-const refのとき`v`がfalseになるようになっている。
## いろんな渡し方
base::OwnedRefの他にもいくつかの渡し方があるので確認する。
### base::Owned
Ownedの例としては以下。
```cpp!
// Refじゃないのでポインタとして受け取る
void foo(int* arg) { std::cout << *arg << std::endl; }
int* pn = new int(1);
RepeatingClosure foo_callback = BindRepeating(&foo, Owned(pn));
// Prints "1"
foo_callback.Run();
foo_callback.Run();
*pn = 2;
// Prints "2"
foo_callback.Run();
// `pn` is deleted.
foo_callback.Reset();
```
所有権をcallbackに渡す。
渡す側が参照を持つ形式。
### base::Passed
Passedはunique_ptrなどcopyはできないがmoveは許されている型のオブジェクトを渡す時に使う。
ちなみに以下のような条件がParamsCanBeBoundにある。
```cpp!
static constexpr bool kWouldBeForwardableWithPassed =
std::is_convertible_v<std::decay_t<ForwardingType>&&,
FunctorParamType>;
```
比較用に、普通にForwardedできる条件は以下。
```cpp!
static constexpr bool kCanBeForwardedToBoundFunctor =
std::is_convertible_v<ForwardingType, FunctorParamType>;
```
passでいけるやつは`&&`、つまりmove operatorならconvertibleのとき。
TODO(elkurin): decay_tは何してる?
## ちなみにstd::ref
[std::ref](https://en.cppreference.com/w/cpp/utility/functional/ref)も参照ラッパーとして変数への参照を保持する標準ライブラリ。
以下は最近書いた使用例。
```cpp
base::ThreadPool::PostTaskAndReply(
FROM_HERE, base::MayBlock(),
base::BindOnce(&DoLacrosBackgroundWorkPreLaunch, lacros_dir,
clear_shared_resource_file, launching_at_login_screen,
std::ref(params)),
base::BindOnce(std::move(callback)));
```
`params`の所有権はどこかに保存したままその参照を`std::ref`で取り出して渡すことでcallbackにも無事渡せている。
返り値はreference_wrapper型。