beman-project / optional26

Beman.Optional26: `std::optional` extensions targeting C++26
Apache License 2.0
13 stars 8 forks source link

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

Open frederick-vs-ja opened 1 month ago

frederick-vs-ja commented 1 month ago

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

```C++ namespace detail { template class optional_value_or_layer {}; template requires (!std::is_function_v && !std::is_array_v) class optional_value_or_layer { public: template constexpr T value_or(U&& u) const { static_assert(std::is_constructible_v, "Must be able to bind u to T&"); const auto& derived_self = static_cast&>(*this); return derived_self.has_value() ? *derived_self.value_ : std::forward(u); } }; template class optional_range_layer {}; template requires (!std::is_function_v && !std::is_unbounded_array_v) class optional_range_layer { public: // Since ${PAPER_NUMBER}: ${PAPER_TITLE}. // Note: P3168 and P2988 may have different flows inside LEWG/LWG. // Implementation of the range support for optional reflects P3168R2 for now. // [optional.iterators], iterator support using iterator = detail::contiguous_iterator>; // see [optional.iterators] using const_iterator = detail::contiguous_iterator>; // 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 reflects P3168R2 for now. // [optional.iterators], iterator support constexpr iterator begin() noexcept { auto& derived_self = static_cast&>(*this); return iterator(derived_self.has_value() ? derived_self.value_ : nullptr); }; constexpr const_iterator begin() const noexcept { const auto& derived_self = static_cast&>(*this); return const_iterator(derived_self.has_value() ? derived_self.value_ : nullptr); }; constexpr iterator end() noexcept { return begin() + static_cast&>(*this).has_value(); } constexpr const_iterator end() const noexcept { return begin() + static_cast&>(*this).has_value(); } }; } // namespace detail template class optional : public detail::optional_value_or_layer, public detail::optional_range_layer { // ... }; ```

Godbolt link for rough test.

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