LoginSignup
0
0

More than 1 year has passed since last update.

C++14で使える簡易版Optional型を自作した

Last updated at Posted at 2022-01-29

概要

C++17で無効値を表すことができるstd::optionalクラスが導入されたが,これに近い機能をC++14で利用するために簡易版mylib::optionalクラスを自作した.

ソースコード

#pragma once

#include <stdexcept>

namespace mylib {

class bad_optional_access : public std::exception {
  public:
    const char* what() const noexcept override {
      return "bad_optional_access";
    }
};

template <typename T>
class optional {
 public:
  /**
   * @brief コンストラクタ.無効値を生成する.
   */
  constexpr optional() noexcept : value_(), has_value_(false) {}

  /**
   * @brief コンストラクタ.有効値を生成する.
   */
  constexpr explicit optional(const T& v) : value_(v), has_value_(true) {}

  /**
   * @brief コピーコンストラクタ
   */
  constexpr optional(const optional& rhs)
      : value_(rhs.value_), has_value_(rhs.has_value_) {}

  /**
   * @brief ムーブコンストラクタ
   */
  constexpr optional(optional&& rhs) noexcept
      : value_(std::move(rhs.value_)), has_value_(rhs.has_value_) {}

  /**
   * @brief デストラクタ
   */
  ~optional() = default;

  /**
   * @brief コピー代入演算子
   */
  optional& operator=(const optional& rhs) {
    if (this != &rhs) {
      value_ = rhs.value_;
      has_value_ = rhs.has_value_;
    }
    return *this;
  }

  /**
   * @brief ムーブ代入演算子
   */
  optional& operator=(optional&& rhs) noexcept {
    if (this != &rhs) {
      value_ = std::move(rhs.value_);
      has_value_ = rhs.has_value_;
    }
    return *this;
  }

  /**
   * @brief 有効値かどうかを返す.
   */
  constexpr explicit operator bool() const noexcept { return has_value_; }

  /**
   * @brief 有効値かどうかを返す.
   */
  constexpr bool has_value() const noexcept { return has_value_; }

  /**
   * @brief メンバアクセス演算子
   */
  constexpr T* operator->() noexcept { return &value_; }

  /**
   * @brief メンバアクセス演算子
   */
  constexpr const T* operator->() const noexcept { return &value_; }

  /**
   * @brief 間接参照演算子(左辺値参照)
   */
  constexpr T& operator*() & noexcept { return value_; }

  /**
   * @brief 間接参照演算子(右辺値参照)
   */
  constexpr T&& operator*() && noexcept { return std::move(value_); };

  /**
   * @brief 間接参照演算子(const左辺値参照)
   */
  constexpr const T& operator*() const& noexcept { return value_; }

  /**
   * @brief 間接参照演算子(const右辺値参照)
   */
  constexpr const T&& operator*() const&& noexcept { return std::move(value_); }

  /**
   * @brief 保持値への左辺値参照を取得する.
   */
  constexpr T& value() & {
    if (!has_value_) {
      throw bad_optional_access();
    }
    return value_;
  }

  /**
   * @brief 保持値への右辺値参照を取得する.
   */
  constexpr T&& value() && {
    if (!has_value_) {
      throw bad_optional_access();
    }
    return std::move(value_);
  }

  /**
   * @brief 保持値へのconst左辺値参照を取得する.
   */
  constexpr const T& value() const& {
    if (!has_value_) {
      throw bad_optional_access();
    }
    return value_;
  }

  /**
   * @brief 保持値へのconst右辺値参照を取得する.
   */
  constexpr const T&& value() const&& {
    if (!has_value_) {
      throw bad_optional_access();
    }
    return std::move(value_);
  }

 private:
  T value_;
  bool has_value_;
};

} // namespace mylib
0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0