Skip to main content
Became Hot Network Question
edited tags
Link
Toby Speight
  • 88.7k
  • 14
  • 104
  • 327
added 12 characters in body
Source Link
#include <memory>
#include <type_traits>
#include <utility>
#include <cassert>

template<typename T>
struct optional {

    optional() noexcept : _engaged(false) {}

    optional(T&& value) noexcept : _value(std::move(value)), _engaged(true) {}

    optional(optional&& rhs) noexcept : _engaged(std::exchange(rhs._engaged, false)) {
        if (_engaged) {
            std::construct_at(std::addressof(_value), std::move(rhs._value));
        }
    }

    optional& operator=(optional&& rhs) noexcept {
        if (this != &rhs) {
            if (rhs._engaged) {
                if (_engaged) {
                    _value = std::move(rhs._value);
                } else {
                    std::construct_at(std::addressof(_value), std::move(rhs._value));
                    _engaged = true;
                }
            } else {
                reset();
            }
            rhs.reset();
        }
        return *this;
    }

    optional(const optional& rhs) noexcept : _engaged(rhs._engaged) {
        if (_engaged) {
            std::construct_at(std::addressof(_value), rhs._value);
        }
    }

    optional& operator=(const optional& rhs) noexcept {
        if (this != &rhs) {
            if (rhs._engaged) {
                if (_engaged) {
                    _value = rhs._value;
                } else {
                    std::construct_at(std::addressof(_value), rhs._value);
                    _engaged = true;
                }
            } else {
                reset();
            }
        }
        return *this;
    }

    ~optional() noexcept { reset(); }

    [[nodiscard]] T& operator*() noexcept { 
        assert(_engaged && "Attempting to access a disengaged optional!");
        return _value; 
    }

    [[nodiscard]] const T& operator*() const noexcept {
        assert(_engaged && "Attempting to access a disengaged optional!");
        return _value; 
    }

    [[nodiscard]] T* operator->() noexcept { 
        assert(_engaged && "Attempting to dereference a disengaged optional!");
        return std::addressof(_value); 
    }

    [[nodiscard]] const T* operator->() const noexcept { 
        assert(_engaged && "Attempting to dereference a disengaged optional!");
        return std::addressof(_value); 
    }

    operator bool() const noexcept {
        return _engaged;
    }

    bool has_value() const noexcept {
        return _engaged;
    }

    template<typename... Args>
    T& emplace(Args... args) {
        reset();
        std::construct_at(std::addressof(_value), std::forward<Args>(args)...);
        _engaged = true;
        return _value;
    }

    template<typename U>
    [[nodiscard]] T value_or(U&& other_value) const & noexcept 
                            requires(std::is_copy_constructible_v<T> && std::is_convertible_v<U&&, T>) {
        return _engaged ? _value : static_cast<T>(std::forward<U>(other_value));
    }

    template<typename U>
    [[nodiscard]] T value_or(U&& other_value) const && noexcept 
                            requires(std::is_move_constructible_v<T> && std::is_convertible_v<U&&, T>) {
        return _engaged ? std::move(_value) : static_cast<T>(std::forward<U>(other_value));
    }

    T& value() & noexcept {
        return _value;
    }

    T&& value() && noexcept {
        return std::move(_value);
    }

    void reset() noexcept {
        if (_engaged) {
            if constexpr (!std::is_trivially_destructible_v<T>) {
                _value.~T();
            }
            _engaged = false;
        }
    }

private:
    union {
        std::byte _null_state;
        T _value;
    };
    bool _engaged;
};
#include <memory>
#include <type_traits>
#include <utility>
#include <cassert>

template<typename T>
struct optional {

    optional() noexcept : _engaged(false) {}

    optional(T&& value) noexcept : _value(std::move(value)), _engaged(true) {}

    optional(optional&& rhs) noexcept : _engaged(std::exchange(rhs._engaged, false)) {
        if (_engaged) {
            std::construct_at(std::addressof(_value), std::move(rhs._value));
        }
    }

    optional& operator=(optional&& rhs) noexcept {
        if (this != &rhs) {
            if (rhs._engaged) {
                if (_engaged) {
                    _value = std::move(rhs._value);
                } else {
                    std::construct_at(std::addressof(_value), std::move(rhs._value));
                    _engaged = true;
                }
            } else {
                reset();
            }
            rhs.reset();
        }
        return *this;
    }

    optional(optional& rhs) noexcept : _engaged(rhs._engaged) {
        if (_engaged) {
            std::construct_at(std::addressof(_value), rhs._value);
        }
    }

    optional& operator=(optional& rhs) noexcept {
        if (this != &rhs) {
            if (rhs._engaged) {
                if (_engaged) {
                    _value = rhs._value;
                } else {
                    std::construct_at(std::addressof(_value), rhs._value);
                    _engaged = true;
                }
            } else {
                reset();
            }
        }
        return *this;
    }

    ~optional() noexcept { reset(); }

    [[nodiscard]] T& operator*() noexcept { 
        assert(_engaged && "Attempting to access a disengaged optional!");
        return _value; 
    }

    [[nodiscard]] const T& operator*() const noexcept {
        assert(_engaged && "Attempting to access a disengaged optional!");
        return _value; 
    }

    [[nodiscard]] T* operator->() noexcept { 
        assert(_engaged && "Attempting to dereference a disengaged optional!");
        return std::addressof(_value); 
    }

    [[nodiscard]] const T* operator->() const noexcept { 
        assert(_engaged && "Attempting to dereference a disengaged optional!");
        return std::addressof(_value); 
    }

    operator bool() const noexcept {
        return _engaged;
    }

    bool has_value() const noexcept {
        return _engaged;
    }

    template<typename... Args>
    T& emplace(Args... args) {
        reset();
        std::construct_at(std::addressof(_value), std::forward<Args>(args)...);
        _engaged = true;
        return _value;
    }

    template<typename U>
    [[nodiscard]] T value_or(U&& other_value) const & noexcept 
                            requires(std::is_copy_constructible_v<T> && std::is_convertible_v<U&&, T>) {
        return _engaged ? _value : static_cast<T>(std::forward<U>(other_value));
    }

    template<typename U>
    [[nodiscard]] T value_or(U&& other_value) const && noexcept 
                            requires(std::is_move_constructible_v<T> && std::is_convertible_v<U&&, T>) {
        return _engaged ? std::move(_value) : static_cast<T>(std::forward<U>(other_value));
    }

    T& value() & noexcept {
        return _value;
    }

    T&& value() && noexcept {
        return std::move(_value);
    }

    void reset() noexcept {
        if (_engaged) {
            if constexpr (!std::is_trivially_destructible_v<T>) {
                _value.~T();
            }
            _engaged = false;
        }
    }

private:
    union {
        std::byte _null_state;
        T _value;
    };
    bool _engaged;
};
#include <memory>
#include <type_traits>
#include <utility>
#include <cassert>

template<typename T>
struct optional {

    optional() noexcept : _engaged(false) {}

    optional(T&& value) noexcept : _value(std::move(value)), _engaged(true) {}

    optional(optional&& rhs) noexcept : _engaged(std::exchange(rhs._engaged, false)) {
        if (_engaged) {
            std::construct_at(std::addressof(_value), std::move(rhs._value));
        }
    }

    optional& operator=(optional&& rhs) noexcept {
        if (this != &rhs) {
            if (rhs._engaged) {
                if (_engaged) {
                    _value = std::move(rhs._value);
                } else {
                    std::construct_at(std::addressof(_value), std::move(rhs._value));
                    _engaged = true;
                }
            } else {
                reset();
            }
            rhs.reset();
        }
        return *this;
    }

    optional(const optional& rhs) noexcept : _engaged(rhs._engaged) {
        if (_engaged) {
            std::construct_at(std::addressof(_value), rhs._value);
        }
    }

    optional& operator=(const optional& rhs) noexcept {
        if (this != &rhs) {
            if (rhs._engaged) {
                if (_engaged) {
                    _value = rhs._value;
                } else {
                    std::construct_at(std::addressof(_value), rhs._value);
                    _engaged = true;
                }
            } else {
                reset();
            }
        }
        return *this;
    }

    ~optional() noexcept { reset(); }

    [[nodiscard]] T& operator*() noexcept { 
        assert(_engaged && "Attempting to access a disengaged optional!");
        return _value; 
    }

    [[nodiscard]] const T& operator*() const noexcept {
        assert(_engaged && "Attempting to access a disengaged optional!");
        return _value; 
    }

    [[nodiscard]] T* operator->() noexcept { 
        assert(_engaged && "Attempting to dereference a disengaged optional!");
        return std::addressof(_value); 
    }

    [[nodiscard]] const T* operator->() const noexcept { 
        assert(_engaged && "Attempting to dereference a disengaged optional!");
        return std::addressof(_value); 
    }

    operator bool() const noexcept {
        return _engaged;
    }

    bool has_value() const noexcept {
        return _engaged;
    }

    template<typename... Args>
    T& emplace(Args... args) {
        reset();
        std::construct_at(std::addressof(_value), std::forward<Args>(args)...);
        _engaged = true;
        return _value;
    }

    template<typename U>
    [[nodiscard]] T value_or(U&& other_value) const & noexcept 
                            requires(std::is_copy_constructible_v<T> && std::is_convertible_v<U&&, T>) {
        return _engaged ? _value : static_cast<T>(std::forward<U>(other_value));
    }

    template<typename U>
    [[nodiscard]] T value_or(U&& other_value) const && noexcept 
                            requires(std::is_move_constructible_v<T> && std::is_convertible_v<U&&, T>) {
        return _engaged ? std::move(_value) : static_cast<T>(std::forward<U>(other_value));
    }

    T& value() & noexcept {
        return _value;
    }

    T&& value() && noexcept {
        return std::move(_value);
    }

    void reset() noexcept {
        if (_engaged) {
            if constexpr (!std::is_trivially_destructible_v<T>) {
                _value.~T();
            }
            _engaged = false;
        }
    }

private:
    union {
        std::byte _null_state;
        T _value;
    };
    bool _engaged;
};
edited tags
Source Link
toolic
  • 16.4k
  • 6
  • 29
  • 221

I'm preparing for entry-level C++ developer interview and decided to implement some of std:: members. Here's my implementation of std::optionalstd::optional. I would be grateful for any feedback to help me improve my implementation.

I'm preparing for entry-level C++ developer interview and decided to implement some of std:: members. Here's my implementation of std::optional. I would be grateful for any feedback to help me improve my implementation.

I'm preparing for entry-level C++ developer interview and decided to implement some of std:: members. Here's my implementation of std::optional. I would be grateful for any feedback to help me improve my implementation.

Source Link
Loading