Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for optional<R(&)(Args...)> and optional<T(&)[N]>/optional<T(&)[]> #55

Open
frederick-vs-ja opened this issue Aug 27, 2024 · 0 comments

Comments

@frederick-vs-ja
Copy link
Contributor

frederick-vs-ja commented Aug 27, 2024

As noticed in steve-downey/optional_ref#20, the value_or member and range interface would be problematic for these types.

I guess we can make value_or and begin etc. conditionally existing as iterator_category for many iterator types.

Expand to see the implementation details

namespace detail {
template <class>
class optional_value_or_layer {};
template <class T>
    requires (!std::is_function_v<T> && !std::is_array_v<T>)
class optional_value_or_layer<T&> {
  public:
    template <class U>
    constexpr T value_or(U&& u) const {
        static_assert(std::is_constructible_v<T&, U>, "Must be able to bind u to T&");
        const auto& derived_self = static_cast<const optional<T&>&>(*this);
        return derived_self.has_value() ? *derived_self.value_ : std::forward<U>(u);
    }
};

template <class>
class optional_range_layer {};
template <class T>
    requires (!std::is_function_v<T> && !std::is_unbounded_array_v<T>)
class optional_range_layer<T&> {
  public:
    // Since ${PAPER_NUMBER}: ${PAPER_TITLE}.
    // Note: P3168 and P2988 may have different flows inside LEWG/LWG.
    // Implementation of the range support for optional<T&> reflects P3168R2 for now.
    // [optional.iterators], iterator support
    using iterator       = detail::contiguous_iterator<T, optional<T&>>;       // see [optional.iterators]
    using const_iterator = detail::contiguous_iterator<const T, optional<T&>>; // see [optional.iterators]

    // Since ${PAPER_NUMBER}: ${PAPER_TITLE}.
    // Note: P3168 and P2988 may have different flows inside LEWG/LWG.
    // Implementation of the range support for optional<T&> reflects P3168R2 for now.
    // [optional.iterators], iterator support
    constexpr iterator       begin() noexcept {
        auto& derived_self = static_cast<optional<T&>&>(*this);
        return iterator(derived_self.has_value() ? derived_self.value_ : nullptr);
    };
    constexpr const_iterator begin() const noexcept {
        const auto& derived_self = static_cast<const optional<T&>&>(*this);
        return const_iterator(derived_self.has_value() ? derived_self.value_ : nullptr);
    };

    constexpr iterator       end() noexcept {
        return begin() + static_cast<const optional<T&>&>(*this).has_value();
    }
    constexpr const_iterator end() const noexcept {
        return begin() + static_cast<const optional<T&>&>(*this).has_value();
    }
};
} // namespace detail

template <class T>
class optional<T&> : public detail::optional_value_or_layer<T&>, public detail::optional_range_layer<T&> {
    // ...
};

Godbolt link for rough test.

Should we make such change (in both beman::optional26::optional and P2988)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant