class alignas()

in folly/Replaceable.h [396:628]


class alignas(T) Replaceable
    : public replaceable_detail::dtor_mixin<T>,
      public replaceable_detail::default_and_move_ctor_mixin<T>,
      public replaceable_detail::copy_ctor_mixin<T>,
      public replaceable_detail::move_assignment_mixin<T>,
      public replaceable_detail::copy_assignment_mixin<T> {
  using ctor_base = replaceable_detail::default_and_move_ctor_mixin<T>;

 public:
  using value_type = T;

  /* Rule-of-zero default- copy- and move- constructors. The ugly code to make
   * these work are above, in namespace folly::replaceable_detail.
   */
  constexpr Replaceable() = default;
  constexpr Replaceable(const Replaceable&) = default;
  constexpr Replaceable(Replaceable&&) = default;

  /* Rule-of-zero copy- and move- assignment operators. The ugly code to make
   * these work are above, in namespace folly::replaceable_detail.
   *
   * Note - these destruct the `T` and then in-place construct a new one based
   * on what is in the other replaceable; they do not invoke the assignment
   * operator of `T`.
   */
  Replaceable& operator=(const Replaceable&) = default;
  Replaceable& operator=(Replaceable&&) = default;

  /* Rule-of-zero destructor. The ugly code to make this work is above, in
   * namespace folly::replaceable_detail.
   */
  ~Replaceable() = default;

  /**
   * Constructors; these are modeled very closely on the definition of
   * `std::optional` in C++17.
   */
  template <
      class... Args,
      std::enable_if_t<std::is_constructible<T, Args&&...>::value, int> = 0>
  constexpr explicit Replaceable(in_place_t, Args&&... args)
      // clang-format off
      noexcept(std::is_nothrow_constructible<T, Args&&...>::value)
      // clang-format on
      : ctor_base(0) {
    ::new (storage_) T(std::forward<Args>(args)...);
  }

  template <
      class U,
      class... Args,
      std::enable_if_t<
          std::is_constructible<T, std::initializer_list<U>, Args&&...>::value,
          int> = 0>
  constexpr explicit Replaceable(
      in_place_t, std::initializer_list<U> il, Args&&... args)
      // clang-format off
      noexcept(std::is_nothrow_constructible<
          T,
          std::initializer_list<U>,
          Args&&...>::value)
      // clang-format on
      : ctor_base(0) {
    ::new (storage_) T(il, std::forward<Args>(args)...);
  }

  template <
      class U = T,
      std::enable_if_t<
          std::is_constructible<T, U&&>::value &&
              !std::is_same<std::decay_t<U>, in_place_t>::value &&
              !std::is_same<Replaceable<T>, std::decay_t<U>>::value &&
              std::is_convertible<U&&, T>::value,
          int> = 0>
  constexpr /* implicit */ Replaceable(U&& other)
      // clang-format off
      noexcept(std::is_nothrow_constructible<T, U&&>::value)
      // clang-format on
      : ctor_base(0) {
    ::new (storage_) T(std::forward<U>(other));
  }

  template <
      class U = T,
      std::enable_if_t<
          std::is_constructible<T, U&&>::value &&
              !std::is_same<std::decay_t<U>, in_place_t>::value &&
              !std::is_same<Replaceable<T>, std::decay_t<U>>::value &&
              !std::is_convertible<U&&, T>::value,
          int> = 0>
  constexpr explicit Replaceable(U&& other)
      // clang-format off
      noexcept(std::is_nothrow_constructible<T, U&&>::value)
      // clang-format on
      : ctor_base(0) {
    ::new (storage_) T(std::forward<U>(other));
  }

  template <
      class U,
      std::enable_if_t<
          std::is_constructible<T, const U&>::value &&
              !replaceable_detail::is_constructible_from_replaceable<
                  T>::value &&
              !replaceable_detail::is_convertible_from_replaceable<T>::value &&
              std::is_convertible<const U&, T>::value,
          int> = 0>
  /* implicit */ Replaceable(const Replaceable<U>& other)
      // clang-format off
      noexcept(std::is_nothrow_constructible<T, U const&>::value)
      // clang-format on
      : ctor_base(0) {
    ::new (storage_) T(*other);
  }

  template <
      class U,
      std::enable_if_t<
          std::is_constructible<T, const U&>::value &&
              !replaceable_detail::is_constructible_from_replaceable<
                  T>::value &&
              !replaceable_detail::is_convertible_from_replaceable<T>::value &&
              !std::is_convertible<const U&, T>::value,
          int> = 0>
  explicit Replaceable(const Replaceable<U>& other)
      // clang-format off
      noexcept(std::is_nothrow_constructible<T, U const&>::value)
      // clang-format on
      : ctor_base(0) {
    ::new (storage_) T(*other);
  }

  template <
      class U,
      std::enable_if_t<
          std::is_constructible<T, U&&>::value &&
              !replaceable_detail::is_constructible_from_replaceable<
                  T>::value &&
              !replaceable_detail::is_convertible_from_replaceable<T>::value &&
              std::is_convertible<U&&, T>::value,
          int> = 0>
  /* implicit */ Replaceable(Replaceable<U>&& other)
      // clang-format off
      noexcept(std::is_nothrow_constructible<T, U&&>::value)
      // clang-format on
      : ctor_base(0) {
    ::new (storage_) T(std::move(*other));
  }

  template <
      class U,
      std::enable_if_t<
          std::is_constructible<T, U&&>::value &&
              !replaceable_detail::is_constructible_from_replaceable<
                  T>::value &&
              !replaceable_detail::is_convertible_from_replaceable<T>::value &&
              !std::is_convertible<U&&, T>::value,
          int> = 0>
  explicit Replaceable(Replaceable<U>&& other)
      // clang-format off
      noexcept(std::is_nothrow_constructible<T, U&&>::value)
      // clang-format on
      : ctor_base(0) {
    ::new (storage_) T(std::move(*other));
  }

  /**
   * `emplace` destructs the contained object and in-place constructs the
   * replacement.
   *
   * The destructor must not throw (as usual). The constructor must not throw
   * because that would violate the invariant that a `Replaceable<T>` always
   * contains a T instance.
   *
   * As these methods are `noexcept` the program will be terminated if an
   * exception is thrown. If you are encountering this issue you should look at
   * using `Optional` instead.
   */
  template <class... Args>
  T& emplace(Args&&... args) noexcept {
    T* destruct_ptr = launder(reinterpret_cast<T*>(storage_));
    destruct_ptr->~T();
    return *::new (storage_) T(std::forward<Args>(args)...);
  }

  template <class U, class... Args>
  T& emplace(std::initializer_list<U> il, Args&&... args) noexcept {
    T* destruct_ptr = launder(reinterpret_cast<T*>(storage_));
    destruct_ptr->~T();
    return *::new (storage_) T(il, std::forward<Args>(args)...);
  }

  /**
   * `swap` just calls `swap(T&, T&)`.
   */
  void swap(Replaceable& other) noexcept(IsNothrowSwappable<Replaceable>{}) {
    using std::swap;
    swap(*(*this), *other);
  }

  /**
   * Methods to access the contained object. Intended to be very unsurprising.
   */
  constexpr const T* operator->() const {
    return launder(reinterpret_cast<T const*>(storage_));
  }

  constexpr T* operator->() { return launder(reinterpret_cast<T*>(storage_)); }

  constexpr const T& operator*() const& {
    return *launder(reinterpret_cast<T const*>(storage_));
  }

  constexpr T& operator*() & {
    return *launder(reinterpret_cast<T*>(storage_));
  }

  constexpr T&& operator*() && {
    return std::move(*launder(reinterpret_cast<T*>(storage_)));
  }

  constexpr const T&& operator*() const&& {
    return std::move(*launder(reinterpret_cast<T const*>(storage_)));
  }

 private:
  friend struct replaceable_detail::dtor_mixin<T>;
  friend struct replaceable_detail::default_and_move_ctor_mixin<T>;
  friend struct replaceable_detail::copy_ctor_mixin<T>;
  friend struct replaceable_detail::move_assignment_mixin<T>;
  friend struct replaceable_detail::copy_assignment_mixin<T>;
  aligned_storage_for_t<T> storage_[1];
};