实现一个 std::optional

实现一个 std::optional

如果写过 c# 或者是 rust ,那么对于里面的可空类型一定是很常用的。在 c++17 中添加了 std::optional ,也就是所谓的可空类型。

不过这里的实现是 placement new 的方式,也是位于栈上。

实现的主要点是申请一块内存空间,由于需要效率,因此这块内存空间的生命周期应当与对象一致,所以这边使用了 std::array 作为代替。

struct NoneOption {
  NoneOption() = default;
} None;

template <typename Ty> class Option {
private:
  using DataByte = std::array<std::uint8_t, sizeof(Ty)>;

public:
  constexpr Option() noexcept : has_value_{false} {}

  constexpr Option(NoneOption) noexcept : Option() {}

  constexpr Option(const Ty &init) : has_value_{true} {
    this->ConstructData(init);
  }

  constexpr Option(Ty &&init) : has_value_{true} {
    this->ConstructData(std::move(init));
  }

  constexpr Option(const Option &other) : has_value_{other.has_value_} {
    if (other.has_value_)
      this->ConstructData(*other);
  }

  constexpr Option(Option &&other) noexcept
      : data_(std::move(other.data_)), has_value_{std::move(other.has_value_)} {
        other.has_value_ = false;
  }

  constexpr auto operator=(const Option &other) -> Option & {
    this->Reset();
    if (other.has_value_)
      this->ConstructData(*other);
    this->has_value_ = other.has_value_;
  }

  constexpr auto operator=(Option &&other) noexcept {
    this->Reset();
    this->data_ = std::move(other.data_);
    this->has_value_ = other.has_value_;
    other.has_value_ = false;
  }

  constexpr ~Option() noexcept {
    this->ReinterpretCastData()->~Ty();
    this->has_value_ = false;
  }

public:
  constexpr auto HasValue() const noexcept -> bool { return this->has_value_; }

  constexpr explicit operator bool() const noexcept { return this->HasValue(); }

public:
  constexpr auto operator->() const noexcept -> const Ty * {
    return this->ReinterpretCastData();
  }

  constexpr auto operator->() noexcept -> Ty * {
    return this->ReinterpretCastData();
  }

  constexpr auto operator*() const & noexcept -> const Ty & {
    return *this->ReinterpretCastData();
  }

  constexpr auto operator*() & noexcept -> Ty & {
    return *this->ReinterpretCastData();
  }

  constexpr auto operator*() const && noexcept -> const Ty && {
    return std::move(*this->ReinterpretCastData());
  }

  constexpr auto operator*() && noexcept -> Ty && {
    return std::move(*this->ReinterpretCastData());
  }

public:
  template <typename... Args> constexpr auto Emplace(Args &&...args) -> void {
    if (this->has_value_) {
      this->Reset();
    }
    this->ConstructData(std::forward<Args>(args)...);
  }

  constexpr auto Reset() noexcept -> void {
    if (this->has_value_) {
      this->ReinterpretCastData()->~Ty();
    }
  }

  constexpr auto Swap(Option &other) noexcept -> void {
    std::swap(this->data_, other.data_);
    std::swap(this->has_value_, other.has_value_);
  }

  constexpr auto Value() const & -> const Ty & {
    if (this->has_value_) {
      return **this;
    }
    throw std::exception();
  }

  constexpr auto Value() const && -> const Ty && {
    if (this->has_value_) {
      return std::move(**this);
    }
    throw std::exception();
  }

  template <typename U>
  constexpr auto ValueOr(U &&default_value) const & -> Ty {
    if (this->has_value_) {
      return **this;
    }
    return static_cast<Ty>(default_value);
  }

  template <typename U> constexpr auto ValueOr(U &&default_value) && -> Ty {
    if (this->has_value_) {
      return std::move(**this);
    }
    return static_cast<Ty>(default_value);
  }

private:
  template <typename... Args>
    requires requires(Args... args) { new Ty(args...); }
  constexpr auto ConstructData(Args &&...args) -> void {
    new (this->data_.data()) Ty(std::forward<Args>(args)...);
  }

  constexpr auto ReinterpretCastData() noexcept -> Ty * {
    return reinterpret_cast<Ty *>(this->data_.data());
  }

  constexpr auto ReinterpretCastData() const noexcept -> const Ty * {
    return reinterpret_cast<const Ty *>(this->data_.data());
  }

private:
  DataByte data_;
  bool has_value_;
};
posted @ 2024-03-10 22:10  フランドール·スカーレット  阅读(53)  评论(0)    收藏  举报