最終更新日時: 2026年04月07日 15時36分39秒 (JST)
Akira Takahashi が更新

履歴 編集

function
<optional>

# std::optional::operator=(C++17)

    optional<T>& operator=(nullopt_t rhs) noexcept;                    // (1) C++17
    constexpr optional<T>& operator=(nullopt_t rhs) noexcept;          // (1) C++23

    optional& operator=(const optional& rhs);                          // (2) C++17
    constexpr optional& operator=(const optional& rhs);                // (2) C++20

    optional& operator=(optional&& rhs) noexcept(see below);           // (3) C++17
    constexpr optional& operator=(optional&& rhs) noexcept(see below); // (3) C++20

    template <class U = T>
    optional& operator=(U&& rhs);                                      // (4) C++17
    template <class U = T>
    constexpr optional& operator=(U&& rhs);                            // (4) C++23

    template <class U>
    optional& operator=(const optional<U>& rhs);                       // (5) C++17
    template <class U>
    constexpr optional& operator=(const optional<U>& rhs);             // (5) C++23

    template <class U>
    optional& operator=(optional<U>&& rhs);                            // (6) C++17
    template <class U>
    constexpr optional& operator=(optional<U>&& rhs);                  // (6) C++23

    // optional<T&>固有のオーバーロード (C++26)
    constexpr optional& operator=(const optional&) noexcept = default; // (7) C++26

## 概要

- (1) : 無効値を代入する
- (2) : コピー代入
- (3) : ムーブ代入
- (4) : 要素型`T`に変換可能な値をムーブ代入
- (5) : `optional<T>`に変換可能な`optional`オブジェクトをコピー代入
- (6) : `optional<T>`に変換可能な`optional`オブジェクトをムーブ代入
- (7) : `optional<T&>`のコピー代入。参照先の再束縛 (rebind) を行う (`noexcept = default`)

`optional<T>`では (1)～(6) が定義される。`optional<T&>`では (1), (7) が定義される。

## テンプレートパラメータ制約

- (4), (5), (6) : 型`U`が型`T`に変換可能であること

## 効果

(1)～(6) では、`*this` と `rhs` が有効な値を持っているか否かによって以下のような挙動となる。

| `*this` が有効な値を持っている | `*this` が有効な値を持っていない
--- | --- | ---
`rhs` が有効な値を持っている | 値の代入が行われる。 | 値の構築が行われる。`has_value()` は `true` となる。
`rhs` が有効な値を持っていない | 値の破棄が行われる。`has_value()` は `false` となる。 | 何も行われない。

なお、(1) では `rhs` は常に有効な値を持っていないとみなされ、また、(4) では `rhs` は常に有効な値を持っているとみなされる。

また、`rhs` が有効な値を持っている場合に `operator=`（代入の場合）、あるいは、コンストラクタ（構築の場合）を呼び出す際の引数は以下となる。

- (2), (5): `*rhs`
- (3), (6): `std::move(*rhs)`
- (4): `std::forward<U>(rhs)`

(7) では、`rhs`が保持する参照先ポインタをコピーする (参照先の再束縛)。

## 戻り値

`*this`

## 例外

共通の動作として、代入演算子内で例外が発生した場合、`has_value()`の結果は変わらない。

- (2) :
  - 型`T`のコピーコンストラクタで例外が発生した場合は、なにも効果がなく終了する。型`T`のコピー代入で例外が発生した場合は、型`T`のコピー代入演算子の例外安全性が保証する動作となる
- (3) :
  - 要素型`T`が、ムーブ代入とムーブ構築で例外を送出しない場合、この関数は決して例外を送出しない
  - 型`T`のムーブコンストラクタで例外が発生した場合、`*rhs.val`の状態は型`T`のムーブコンストラクタの例外安全性によって決定される
- (4), (5), (6) :
  - 型`T`のコンストラクタもしくは代入演算子で例外が発生した場合、それらの関数の例外安全性が保証する動作となる

## delete定義される条件

- (2) : 型`T`がコピー構築可能でなく、コピー代入可能でもないこと
- (3) : 型`T`がムーブ構築可能でなく、ムーブ代入可能でもないこと

## トリビアルに定義される条件

- (2) : 型`T`が、トリビアルにコピー構築可能でありトリビアルにコピー代入可能かつ、トリビアルに破棄可能である
- (3) : 型`T`が、トリビアルにムーブ構築可能でありトリビアルにムーブ代入可能かつ、トリビアルに破棄可能である

## 備考

- (7) : `optional<T&>`への代入は、参照先オブジェクトへの代入ではなく、参照先の再束縛 (rebind) を行う。これはポインタの代入と同じセマンティクスである
- `optional<T&>`では、値の代入や異なる型の`optional`からの変換代入は提供されない。値を代入する場合は、暗黙の変換による`optional<T&>`の構築とコピー代入 (7) を通じて行われる

## 例

    #include <cassert>
    #include <optional>
    #include <utility>

    int main()
    {
      // (1)
      // 無効値を代入
      {
        std::optional<int> p = 3;

        p = std::nullopt;
        assert(!p.has_value());
      }

      // (2)
      // コピー代入
      {
        std::optional<int> a = 3;
        std::optional<int> b = 1;

        a = b;
        assert(a.value() == 1);
      }

      // (3)
      // ムーブ代入
      {
        std::optional<int> a = 3;
        std::optional<int> b = 1;

        a = std::move(b);
        assert(a.value() == 1);
      }

      // (4)
      // 有効値をコピー代入もしくはムーブ代入
      {
        std::optional<int> p;

        p = 3;
        assert(p.has_value());
        assert(p.value() == 3);
      }

      // (5)
      // 変換可能なoptionalオブジェクトをコピー代入
      {
        std::optional<long long> a = 3LL;
        std::optional<int> b = 1;

        a = b;
        assert(a.value() == 1LL);
      }

      // (6)
      // 変換可能なoptionalオブジェクトをムーブ代入
      {
        std::optional<long long> a = 3LL;
        std::optional<int> b = 1;

        a = std::move(b);
        assert(a.value() == 1LL);
      }
    }

### 出力

## バージョン

### 言語

- C++17

### 処理系

- GCC: 7.2 ✅
- Clang: 4.0.1 ✅
- ICC: ?
- Visual C++: ??

## 参照

- LWG Issue 2756. `optional<T>` should `forward T`'s implicit conversions
- P0602R4 `variant` and `optional` should propagate copy/move triviality
- P2231R1 Missing `constexpr` in `std::optional` and `std::variant`
- P2988R12 `std::optional<T&>`
  - C++26で参照型`T&`に対する部分特殊化を追加