# std::optional の operator 値があったりなかったりする[std::optional](https://en.cppreference.com/w/cpp/utility/optional)型の等号や比較演算子の挙動を確認する。 標準ライブラリのcoding styleが読みにくいのでほぼ同じであろうabseilを読みます。 ## operator== `==`を使うときにnullチェックを行って書いてきたのだが、どうやらいらないということを知った。 それが今日このノートを書くきっかけ。 まずstd::optional型同士の比較について。 ```cpp template <typename T, typename U> constexpr auto operator==(const optional<T>& x, const optional<U>& y) -> decltype(optional_internal::convertible_to_bool(*x == *y)) { return static_cast<bool>(x) != static_cast<bool>(y) ? false : static_cast<bool>(x) == false ? true : static_cast<bool>(*x == *y); } ``` boolにキャストして、その値同士が違うならfalse。つまり、値のあるなしが一致しない場合は即座にfalseを返す。 そうでない場合、xのboolがfalseなら、つまりどちらもnullってことなので、それは同値とみなしtrueを返す。 そうでない場合は有効値があるので、その値同士を比較する。 なお2つの値のどちらかがnulloptでどちらかがそうでない場合、以下の関数がオーバーロードされfalseを返す。 ```cpp template <typename T> constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept { return !x; } template <typename T> constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept { return !x; } ``` さらにstd::optional型と中身の型でも比較できる。 `optional_internal::convertible_to_bool(*x == v)`でbool値に変換できるかを確認している。 `*x`と`v`の型が一致しているかを確認するためのヘルパーでもある。 ```cpp template <typename T, typename U> constexpr auto operator==(const optional<T>& x, const U& v) -> decltype(optional_internal::convertible_to_bool(*x == v)) { return static_cast<bool>(x) ? static_cast<bool>(*x == v) : false; } template <typename T, typename U> constexpr auto operator==(const U& v, const optional<T>& x) -> decltype(optional_internal::convertible_to_bool(v == *x)) { return static_cast<bool>(x) ? static_cast<bool>(v == *x) : false; } ``` この場合はシンプルにnullでないときに中身の値を比較するだけで良い。 ## 比較演算子 operator< も operator== と同じ。 値があるなら比較し、そうでない場合 値なし<値ありとしている。 ```cpp template <typename T, typename U> constexpr auto operator<(const optional<T>& x, const optional<U>& y) -> decltype(optional_internal::convertible_to_bool(*x < *y)) { return !y ? false : !x ? true : static_cast<bool>(*x < *y); } ``` もし`y`が値なしならfalse。 `y`に値があって`x`に値がないならtrue。 どちらにも値があるなら`x`の値と`y`の値を比較する。