最終更新日時(UTC):
が更新

履歴 編集

function
<expected>

std::expected::operator=(C++23)

constexpr expected& operator=(const expected& rhs);    // (1)

constexpr expected& operator=(expected&& rhs) noexcept(see below); // (2)

template<class U = T>
constexpr expected& operator=(U&& v);                  // (3)

template<class G>
constexpr expected& operator=(const unexpected<G>& e); // (4)

template<class G>
constexpr expected& operator=(unexpected<G>&& e);      // (5)

概要

  • (1) : コピー代入。
  • (2) : ムーブ代入。
  • (3) : 要素型Tに変換可能な値を、正常値としてコピー代入またはムーブ代入。
  • (4) : 変換可能なunexpectedオブジェクトから、エラー値としてコピー代入。
  • (5) : 変換可能なunexpectedオブジェクトから、エラー値としてムーブ代入。

動作説明用のexpectedクラスメンバ変数として、下記を導入する。

  • val : T型の正常値。
  • unex : E型のエラー値。
  • has_val : bool型のフラグ変数。正常値を保持する場合はtrueに、エラー値を保持する場合はfalseとなる。

また、説明用のテンプレート関数reinit-expectedを次の通り定義する。

template<class T, class U, class... Args>
constexpr void reinit-expected(T& newval, U& oldval, Args&&... args) {
  if constexpr (is_nothrow_constructible_v<T, Args...>) {
    destroy_at(addressof(oldval));
    construct_at(addressof(newval), std::forward<Args>(args)...);
  } else if constexpr (is_nothrow_move_constructible_v<T>) {
    T tmp(std::forward<Args>(args)...);
    destroy_at(addressof(oldval));
    construct_at(addressof(newval), std::move(tmp));
  } else {
    U tmp(std::move(oldval));
    destroy_at(addressof(oldval));
    try {
      construct_at(addressof(newval), std::forward<Args>(args)...);
    } catch (...) {
      construct_at(addressof(oldval), std::move(tmp));
      throw;
    }
  }
}

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

効果

  • (1) : 次の処理を行ったのち、例外が送出されなければ、has_val = rhs.has_value(); return *this;
    • thisrhsが共に正常値を保持していたら、val = *rhs
    • thisが正常値を保持し、rhsがエラー値を保持していたら、reinit-expected(unex, val, rhs.error())
    • thisがエラーを保持し、rhsが正常値を保持していたら、reinit-expected(val, unex, *rhs)
    • thisrhsが共にエラー値を保持していたら、unex = rhs.error()
  • (2) : 次の処理を行ったのち、例外が送出されなければ、has_val = rhs.has_value(); return *this;
    • thisrhsが共に正常値を保持していたら、val = std::move(*rhs)
    • thisが正常値を保持し、rhsがエラー値を保持していたら、reinit-expected(unex, val, std::move(rhs.error()))
    • thisがエラーを保持し、rhsが正常値を保持していたら、reinit-expected(val, unex, std::move(*rhs))
    • thisrhsが共にエラー値を保持していたら、unex = std::move(rhs.error())
  • (3) : 次の処理と等価
    • thisが正常値を保持していたら、val = std::forward<U>(v)
    • thisがエラー値を保持していたら、reinit-expected(val, unex, std::forward<U>(v)); has_val = true;
  • (4) : 次の処理と等価
    • thisが正常値を保持していたら、reinit-expected(unex, val, std::forward<const G&>(e.error())); has_val = false;
    • thisがエラー値を保持していたら、unex = std::forward<const G&>(e.error());
  • (5) : 次の処理と等価
    • thisが正常値を保持していたら、reinit-expected(unex, val, std::forward<G>(e.error())); has_val = false;
    • thisがエラー値を保持していたら、unex = std::forward<G>(e.error());

戻り値

*this

例外

delete定義される条件

#include <cassert>
#include <expected>
#include <memory>
#include <string>
#include <tuple>
#include <utility>

// std::pair型から2要素std::tuple型へはコピー代入可能
using IntPair  = std::pair<int, int>;
using IntTuple = std::tuple<int, int>;

// std::unique_ptr型からstd::shared_ptr型へはムーブ代入可能
using UniquePtr = std::unique_ptr<int>;
using SharedPtr = std::shared_ptr<int>;

int main()
{
  // (1) コピー代入
  {
    std::expected<int, std::string> srcV = 42;
    std::expected<int, std::string> dstV;
    dstV = srcV;
    assert(srcV.has_value() && dstV.has_value());
    assert(srcV.value() == 42 && dstV.value() == 42);

    std::expected<int, std::string> srcE = std::unexpected{"Oops"};
    std::expected<int, std::string> dstE;
    dstE = srcE;
    assert(!srcE.has_value() && !dstE.has_value());
    assert(srcE.error() == "Oops" && dstE.error() == "Oops");
  }

  // (2) ムーブ代入
  {
    std::expected<std::string, int> srcV = "ok";
    std::expected<std::string, int> dstV;
    dstV = std::move(srcV);
    assert(srcV.has_value() && dstV.has_value());
    assert(dstV.value() == "ok");
    // srcV.value()はstd::stringムーブ後の未規定の値

    std::expected<int, std::string> srcE = std::unexpected{"ng"};
    std::expected<int, std::string> dstE;
    dstE = std::move(srcE);
    assert(!srcE.has_value() && !dstE.has_value());
    assert(dstE.error() == "ng");
    // srcE.error()はstd::stringムーブ後の未規定の値
  }

  // (3) 正常値の変換コピー代入
  {
    IntPair src = IntPair{1, 2};
    std::expected<IntTuple, int> dst;
    dst = src;
    assert(dst.has_value());
    assert((dst.value() == IntTuple{1, 2}));
  }
  // (3) 正常値の変換ムーブ代入
  {
    UniquePtr src = std::make_unique<int>(42);
    std::expected<SharedPtr, int> dst;
    dst = std::move(src);
    assert(dst.has_value());
    assert(*dst.value() == 42);
  }

  // (4) エラー値の変換コピー代入
  {
    std::unexpected<IntPair> src{IntPair{1, 2}};
    std::expected<int, IntTuple> dst;
    dst = src;
    assert(not dst.has_value());
    assert((dst.error() == IntTuple{1, 2}));
  }

  // (5) エラー値の変換ムーブ代入
  {
    std::unexpected<UniquePtr> src{std::make_unique<int>(42)};
    std::expected<int, SharedPtr> dst;
    dst = std::move(src);
    assert(not dst.has_value());
    assert(*dst.error() == 42);
  }
}

出力

バージョン

言語

  • C++23

処理系

参照