Class reference_optional_storage

Synopsis

#include <include/type_safe/optional_ref.hpp>

template <typename T, bool XValue /* = false*/>
class reference_optional_storage

Description

A StoragePolicy for [ts::basic_optional]() that allows optional references.

The actual value_type passed to the optional is [ts::object_ref](), but the reference types are normal references, so value() will return a T& and value_or() takes a fallback reference of the same type and returns one of them. Assigning an optional will always change the target of the reference. You cannot pass rvalues.

If XValue is true, you still cannot pass rvalues, but the result of value()/value_or() will return an rvalue reference, to allow moving of the stored value into something else.

Depending on the const-ness of T is the reference to const or non-const as well, unless XValue is true, in which caseTmust not beconst`. \module optional

Methods

reference_optional_storage\effects Creates it without a bound reference.
copy_value\effects Binds the reference to the same reference in other.
create_value overload\effects Binds the same reference as stored in the optional
create_value overload\effects Binds the reference to the same reference as in other.
create_value overload\effects Binds the reference to the same reference as in ref.
create_value overload\effects Same as destroy_value().
create_value_explicit overload\effects Binds the reference to obj
destroy_value\effects Unbinds the reference.
get_valueReturns: The target of the reference
get_value_or overloadReturns: Either get_value() or other
has_valueReturns: true if the reference is bound, false otherwise.
swap_value\effects Swaps the reference with the reference in other, i.e

Source

Lines 44-155 in include/type_safe/optional_ref.hpp.

template <typename T, bool XValue /* = false*/>
class reference_optional_storage
{
    static_assert(!std::is_reference<T>::value, "pass the type without reference");
    static_assert(!XValue || !std::is_const<T>::value, "must not be const if xvalue reference");

    using result_type = typename std::conditional<XValue, T&&, T&>::type;

    struct prevent_rvalues
    {};

public:
    using value_type             = object_ref<T, XValue>;
    using lvalue_reference       = T&;
    using const_lvalue_reference = lvalue_reference;
    /// \exclude target
    using rvalue_reference       = prevent_rvalues;
    using const_rvalue_reference = rvalue_reference;

    template <typename U>
    using rebind = reference_optional_storage<U, XValue>;

    /// \effects Creates it without a bound reference.
    reference_optional_storage() noexcept : pointer_(nullptr) {}

    /// \effects Binds the same reference as stored in the optional.
    /// \notes This function only participates in overload resolution, if `U` is a reference
    /// compatible with `T`. \param 1 \exclude
    template <typename U, typename = decltype(std::declval<T*&>() = std::declval<U*>())>
    void create_value(const basic_optional<reference_optional_storage<U, XValue>>& ref)
    {
        pointer_ = ref.has_value() ? &ref.value() : nullptr;
    }

    /// \effects Binds the reference to the same reference as in `other`.
    void create_value(const reference_optional_storage& other) noexcept
    {
        pointer_ = other.pointer_;
    }

    /// \effects Binds the reference to the same reference as in `ref`.
    void create_value(const object_ref<T, XValue>& other) noexcept
    {
        pointer_ = other.operator->();
    }

    /// \effects Same as `destroy_value()`.
    void create_value(std::nullptr_t) noexcept
    {
        destroy_value();
    }

    /// \effects Binds the reference to `obj`.
    /// \notes This function only participates in overload resolution, if `U` is a reference
    /// compatible with `T`. \param 1 \exclude
    template <typename U, typename = decltype(std::declval<T*&>() = std::declval<U*>())>
    void create_value_explicit(U& obj) noexcept
    {
        pointer_ = &obj;
    }

    void create_value_explicit(T&&) = delete;

    /// \effects Binds the reference to the same reference in `other`.
    void copy_value(const reference_optional_storage& other) noexcept
    {
        pointer_ = other.pointer_;
    }

    /// \effects Swaps the reference with the reference in `other`,
    /// i.e. rebinds them, no value change.
    void swap_value(reference_optional_storage& other) noexcept
    {
        std::swap(pointer_, other.pointer_);
    }

    /// \effects Unbinds the reference.
    void destroy_value() noexcept
    {
        pointer_ = nullptr;
    }

    /// \returns `true` if the reference is bound, `false` otherwise.
    bool has_value() const noexcept
    {
        return pointer_ != nullptr;
    }

    /// \returns The target of the reference.
    /// Depending on `XValue`, this will either be `T&` or `T&&`.
    /// \exclude return
    result_type get_value() const noexcept
    {
        return static_cast<result_type>(*pointer_);
    }

    /// \returns Either `get_value()` or `other`.
    /// This must be given an lvalue of type `T` and it returns either an lvalue or an rvalue,
    /// depending on `XValue`.
    /// \exclude return
    result_type get_value_or(lvalue_reference other) const noexcept
    {
        if (has_value())
            return get_value();
        return detail::move_if(std::integral_constant<bool, XValue>{}, other);
    }

    result_type get_value_or(T&&) const = delete;

private:
    T* pointer_;
};





Add Discussion as Guest

Log in