diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ed9ea600..55fd9cd8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ This is for working *on* libfn; to *use* the library, see the [README](README.md ## Development environment -Building and testing libfn needs a C++20 toolchain (with one exception). `pfn` polyfills the C++23 standard-library utilities that `fn` builds on (`pfn::expected`, `pfn::invoke_r`, `pfn::unreachable`). The minimum supported compilers are [gcc 12][gcc-standard-support] and [clang 16][clang-standard-support]; if your OS does not ship one recent enough, use the [devcontainer] or [Nix][nix] (see [nix/README.md][nixmd]). You may also use Apple Clang 16.0 or Microsoft Visual Studio 2022 or newer. +Building and testing libfn needs a C++20 toolchain (with one exception). `pfn` polyfills C++23/26 standard-library utilities (`pfn::expected`, `pfn::optional`, `pfn::invoke_r`, `pfn::unreachable`); `fn` builds on `pfn` rather than the newer standard library. The minimum supported compilers are [gcc 12][gcc-standard-support] and [clang 16][clang-standard-support]; if your OS does not ship one recent enough, use the [devcontainer] or [Nix][nix] (see [nix/README.md][nixmd]). You may also use Apple Clang 16.0 or Microsoft Visual Studio 2022 or newer. When working with `tests/pfn/expected.cpp` you will need a C++23 compiler, in order to enable the `VALIDATE_CXX23` option for `expected_validation.cpp` tests. diff --git a/include/fn/expected.hpp b/include/fn/expected.hpp index 3cfb7aeb..2dc0d227 100644 --- a/include/fn/expected.hpp +++ b/include/fn/expected.hpp @@ -41,8 +41,8 @@ struct expected_policy { // Storage layer for ::fn::expected. Inherits the standard-conformant base from // pfn, then hides the four monadic static helpers with sum-widening variants // that materialise their result via `expected_policy::template type`. -template struct _storage : ::pfn::detail::_storage { - using _pfn_base = ::pfn::detail::_storage; +template struct _expected_base : ::pfn::detail::_expected_base { + using _pfn_base = ::pfn::detail::_expected_base; using _pfn_base::_pfn_base; // and_then, non-void value type @@ -248,8 +248,8 @@ template struct _storage : ::pfn::detail::_storage struct expected : private detail::_storage { - using _base = detail::_storage; +template struct expected : private detail::_expected_base { + using _base = detail::_expected_base; using value_type = T; using error_type = Err; using unexpected_type = ::pfn::unexpected; @@ -257,9 +257,9 @@ template struct expected : private detail::_storage using rebind = expected; - // Allow sibling _storage instantiations to downcast into the private base. - template friend struct ::pfn::detail::_storage; - template friend struct ::fn::detail::_storage; + // Allow sibling _expected_base instantiations to downcast into the private base. + template friend struct ::pfn::detail::_expected_base; + template friend struct ::fn::detail::_expected_base; // Constructors. Explicit forwarders to the base mirror pfn::expected. constexpr expected() noexcept(::std::is_nothrow_default_constructible_v) @@ -414,7 +414,7 @@ template struct expected : private detail::_storage; using _base::operator bool; @@ -425,10 +425,10 @@ template struct expected : private detail::_storage && ::std::is_nothrow_swappable_v && ::std::is_nothrow_move_constructible_v && ::std::is_nothrow_swappable_v) @@ -439,7 +439,7 @@ template struct expected : private detail::_storage_swap_with(rhs); } - // Monadic operations. Bodies delegate to _storage static helpers, which perform sum-widening. + // Monadic operations. Bodies delegate to _expected_base static helpers, which perform sum-widening. template constexpr auto and_then(F &&f) & // noexcept(noexcept(_base::_and_then(*this, FWD(f)))) // extension @@ -636,16 +636,16 @@ template struct expected : private detail::_storage struct expected : private detail::_storage { - using _base = detail::_storage; +template struct expected : private detail::_expected_base { + using _base = detail::_expected_base; using value_type = void; using error_type = Err; using unexpected_type = ::pfn::unexpected; template using rebind = expected; - template friend struct ::pfn::detail::_storage; - template friend struct ::fn::detail::_storage; + template friend struct ::pfn::detail::_expected_base; + template friend struct ::fn::detail::_expected_base; constexpr expected() noexcept : _base(::std::in_place) {} @@ -766,7 +766,7 @@ template struct expected : private detail::_storage constexpr auto and_then(F &&f) & // noexcept(noexcept(_base::_and_then(*this, FWD(f)))) // extension diff --git a/include/pfn/expected.hpp b/include/pfn/expected.hpp index 9cd1425e..4c3c8b07 100644 --- a/include/pfn/expected.hpp +++ b/include/pfn/expected.hpp @@ -194,13 +194,13 @@ constexpr bool _is_valid_expected = // // Internal union wrapper for the value/error storage. Copy/move ctors // are defaulted iff both `T` and `E` are trivially copy/move-constructible. -template union _storage_union_t { +template union _expected_union_t { using _value_t = T; T v_; E e_; template - constexpr explicit _storage_union_t(bool s, S &&src) // + constexpr explicit _expected_union_t(bool s, S &&src) // noexcept(::std::is_nothrow_constructible_v && ::std::is_nothrow_constructible_v) { @@ -210,36 +210,36 @@ template union _storage_union_t { ::std::construct_at(::std::addressof(e_), FWD(src).e_); } - constexpr _storage_union_t(_storage_union_t const &) = delete; - constexpr _storage_union_t(_storage_union_t const &) // + constexpr _expected_union_t(_expected_union_t const &) = delete; + constexpr _expected_union_t(_expected_union_t const &) noexcept // requires(::std::is_trivially_copy_constructible_v && ::std::is_trivially_copy_constructible_v) = default; - constexpr _storage_union_t(_storage_union_t &&) = delete; - constexpr _storage_union_t(_storage_union_t &&) // + constexpr _expected_union_t(_expected_union_t &&) = delete; + constexpr _expected_union_t(_expected_union_t &&) noexcept // requires(::std::is_trivially_move_constructible_v && ::std::is_trivially_move_constructible_v) = default; - constexpr _storage_union_t &operator=(_storage_union_t const &) = delete; - constexpr _storage_union_t &operator=(_storage_union_t &&) = delete; + constexpr _expected_union_t &operator=(_expected_union_t const &) = delete; + constexpr _expected_union_t &operator=(_expected_union_t &&) = delete; template - constexpr explicit _storage_union_t(::std::in_place_t /*ignored*/, Args &&...a) // + constexpr explicit _expected_union_t(::std::in_place_t /*ignored*/, Args &&...a) // noexcept(::std::is_nothrow_constructible_v) requires ::std::is_constructible_v : v_(FWD(a)...) { } template - constexpr explicit _storage_union_t(unexpect_t /*ignored*/, Args &&...a) // + constexpr explicit _expected_union_t(unexpect_t /*ignored*/, Args &&...a) // noexcept(::std::is_nothrow_constructible_v) requires ::std::is_constructible_v : e_(FWD(a)...) { } - constexpr ~_storage_union_t() noexcept + constexpr ~_expected_union_t() noexcept requires(::std::is_trivially_destructible_v && ::std::is_trivially_destructible_v) = default; - constexpr ~_storage_union_t() noexcept {} + constexpr ~_expected_union_t() noexcept {} // [expected.object.assign], implementation of reinit-expected template @@ -296,7 +296,7 @@ template union _storage_union_t { } }; -template union _storage_union_t { +template union _expected_union_t { // _dummy_t placeholder, so the union always has an active member struct _dummy_t final { constexpr _dummy_t() noexcept = default; @@ -307,7 +307,7 @@ template union _storage_union_t { E e_; template - constexpr explicit _storage_union_t(bool s, S &&src) // + constexpr explicit _expected_union_t(bool s, S &&src) // noexcept(::std::is_nothrow_constructible_v) { if (s) @@ -316,31 +316,31 @@ template union _storage_union_t { ::std::construct_at(::std::addressof(e_), FWD(src).e_); } - constexpr _storage_union_t(_storage_union_t const &) = delete; - constexpr _storage_union_t(_storage_union_t const &) // + constexpr _expected_union_t(_expected_union_t const &) = delete; + constexpr _expected_union_t(_expected_union_t const &) noexcept // requires(::std::is_trivially_copy_constructible_v) = default; - constexpr _storage_union_t(_storage_union_t &&) = delete; - constexpr _storage_union_t(_storage_union_t &&) // + constexpr _expected_union_t(_expected_union_t &&) = delete; + constexpr _expected_union_t(_expected_union_t &&) noexcept // requires(::std::is_trivially_move_constructible_v) = default; - constexpr _storage_union_t &operator=(_storage_union_t const &) = delete; - constexpr _storage_union_t &operator=(_storage_union_t &&) = delete; + constexpr _expected_union_t &operator=(_expected_union_t const &) = delete; + constexpr _expected_union_t &operator=(_expected_union_t &&) = delete; - constexpr explicit _storage_union_t(::std::in_place_t /*ignored*/) noexcept : v_{} {} + constexpr explicit _expected_union_t(::std::in_place_t /*ignored*/) noexcept : v_{} {} template - constexpr explicit _storage_union_t(unexpect_t /*ignored*/, Args &&...a) // + constexpr explicit _expected_union_t(unexpect_t /*ignored*/, Args &&...a) // noexcept(::std::is_nothrow_constructible_v) requires ::std::is_constructible_v : e_(FWD(a)...) { } - constexpr ~_storage_union_t() noexcept + constexpr ~_expected_union_t() noexcept requires(::std::is_trivially_destructible_v) = default; - constexpr ~_storage_union_t() noexcept {} + constexpr ~_expected_union_t() noexcept {} // [expected.void.assign] mandates direct construction (no temporary). template @@ -365,13 +365,13 @@ template union _storage_union_t { } }; -template constexpr bool _is_storage_union = false; -template constexpr bool _is_storage_union<_storage_union_t> = true; +template constexpr bool _is_expected_union = false; +template constexpr bool _is_expected_union<_expected_union_t> = true; // Shared implementation base class for ::pfn::expected, both primary template // and void specialization. Members are public since inheritance is private. -template struct _storage { - using _storage_t = _storage_union_t; +template struct _expected_base { + using _storage_t = _expected_union_t; // `_value_t` is `T` for non-void, and trivial `_dummy_t` for void. using _value_t = _storage_t::_value_t; _storage_t storage_; @@ -438,10 +438,10 @@ template struct _storage { // Shared construction helper used by both the converting copy/move ctors // and same-type non-trivial copy/move ctors. Delegates the union's - // member selection to _storage_union_t(bool, S&&), based on first parameter. + // member selection to _expected_union_t(bool, S&&), based on first parameter. template - constexpr explicit _storage(bool s, S &&src) - requires(_is_storage_union<::std::remove_cvref_t>) + constexpr explicit _expected_base(bool s, S &&src) + requires(_is_expected_union<::std::remove_cvref_t>) : storage_(s, FWD(src)), set_(s) { } @@ -449,28 +449,28 @@ template struct _storage { // The wrapper's default, value (U&&) and unexpected converting ctors forward directly to the // in_place / unexpect overloads below, so no dedicated overloads for those are provided here. template - constexpr explicit _storage(::std::in_place_t /*ignored*/, Args &&...a) // + constexpr explicit _expected_base(::std::in_place_t /*ignored*/, Args &&...a) // noexcept(::std::is_nothrow_constructible_v<_storage_t, ::std::in_place_t, Args...>) requires ::std::is_constructible_v<_storage_t, ::std::in_place_t, Args...> : storage_(::std::in_place, FWD(a)...), set_(true) { } template - constexpr explicit _storage(::std::in_place_t /*ignored*/, ::std::initializer_list il, Args &&...a) // + constexpr explicit _expected_base(::std::in_place_t /*ignored*/, ::std::initializer_list il, Args &&...a) // noexcept(::std::is_nothrow_constructible_v<_storage_t, ::std::in_place_t, ::std::initializer_list &, Args...>) requires ::std::is_constructible_v<_storage_t, ::std::in_place_t, ::std::initializer_list &, Args...> : storage_(::std::in_place, il, FWD(a)...), set_(true) { } template - constexpr explicit _storage(unexpect_t /*ignored*/, Args &&...a) // + constexpr explicit _expected_base(unexpect_t /*ignored*/, Args &&...a) // noexcept(::std::is_nothrow_constructible_v) requires ::std::is_constructible_v : storage_(unexpect, FWD(a)...), set_(false) { } template - constexpr explicit _storage(unexpect_t /*ignored*/, ::std::initializer_list il, Args &&...a) // + constexpr explicit _expected_base(unexpect_t /*ignored*/, ::std::initializer_list il, Args &&...a) // noexcept(::std::is_nothrow_constructible_v &, Args...>) requires ::std::is_constructible_v &, Args...> : storage_(unexpect, il, FWD(a)...), set_(false) @@ -482,23 +482,23 @@ template struct _storage { template constexpr explicit(not ::std::is_convertible_v<::std::add_lvalue_reference_t<::std::add_const_t>, T> || not ::std::is_convertible_v) - _storage(typename Policy::template type const &s) // + _expected_base(typename Policy::template type const &s) // noexcept((::std::is_void_v || ::std::is_nothrow_constructible_v<_value_t, ::std::add_lvalue_reference_t<::std::add_const_t>>) && ::std::is_nothrow_constructible_v) // extension requires(_can_copy_convert::value) - : _storage(static_cast<_storage const &>(s).set_, - static_cast<_storage const &>(s).storage_) + : _expected_base(static_cast<_expected_base const &>(s).set_, + static_cast<_expected_base const &>(s).storage_) { } template constexpr explicit(not ::std::is_convertible_v || not ::std::is_convertible_v) - _storage(typename Policy::template type &&s) // + _expected_base(typename Policy::template type &&s) // noexcept((::std::is_void_v || ::std::is_nothrow_constructible_v<_value_t, U>) // &&::std::is_nothrow_constructible_v) // extension requires(_can_move_convert::value) - : _storage(static_cast<_storage &&>(s).set_, - ::std::move(static_cast<_storage &&>(s).storage_)) + : _expected_base(static_cast<_expected_base &&>(s).set_, + ::std::move(static_cast<_expected_base &&>(s).storage_)) { } @@ -541,27 +541,27 @@ template struct _storage { } } - constexpr _storage(_storage const &) = default; - constexpr _storage(_storage &&) = default; - constexpr _storage &operator=(_storage const &) = delete; - constexpr _storage &operator=(_storage &&) = delete; + constexpr _expected_base(_expected_base const &) noexcept = default; + constexpr _expected_base(_expected_base &&) noexcept = default; + constexpr _expected_base &operator=(_expected_base const &) = delete; + constexpr _expected_base &operator=(_expected_base &&) = delete; - constexpr ~_storage() // + constexpr ~_expected_base() // requires(::std::is_trivially_destructible_v<_value_t> && ::std::is_trivially_destructible_v) = default; - constexpr ~_storage() // + constexpr ~_expected_base() // requires(::std::is_trivially_destructible_v<_value_t> && not ::std::is_trivially_destructible_v) { if (not set_) ::std::destroy_at(::std::addressof(storage_.e_)); } - constexpr ~_storage() // + constexpr ~_expected_base() // requires(not ::std::is_trivially_destructible_v<_value_t> && ::std::is_trivially_destructible_v) { if (set_) ::std::destroy_at(::std::addressof(storage_.v_)); } - constexpr ~_storage() // + constexpr ~_expected_base() // requires(not ::std::is_trivially_destructible_v<_value_t> && not ::std::is_trivially_destructible_v) { if (set_) @@ -737,26 +737,26 @@ template struct _storage { template static constexpr auto _and_then(Self &&self, Fn &&fn) // - noexcept(::std::is_nothrow_invocable_v - && ::std::is_nothrow_constructible_v) - requires(not ::std::is_void_v && ::std::is_invocable_v - && ::std::is_constructible_v) + noexcept(::std::is_nothrow_invocable_v + && ::std::is_nothrow_constructible_v) + requires(not ::std::is_void_v && ::std::is_invocable_v + && ::std::is_constructible_v) { - using result_t = ::std::remove_cvref_t<::std::invoke_result_t>; + using result_t = ::std::remove_cvref_t<::std::invoke_result_t>; static_assert(Policy::template is_specialization); static_assert(::std::is_same_v::error_type>); if (self.has_value()) { - return ::std::invoke(FWD(fn), _storage::_value(FWD(self))); + return ::std::invoke(FWD(fn), _expected_base::_value(FWD(self))); } - return result_t(unexpect, _storage::_error(FWD(self))); + return result_t(unexpect, _expected_base::_error(FWD(self))); } template static constexpr auto _and_then(Self &&self, Fn &&fn) // noexcept(::std::is_nothrow_invocable_v - && ::std::is_nothrow_constructible_v) + && ::std::is_nothrow_constructible_v) requires(::std::is_void_v && ::std::is_invocable_v - && ::std::is_constructible_v) + && ::std::is_constructible_v) { using result_t = ::std::remove_cvref_t<::std::invoke_result_t>; static_assert(Policy::template is_specialization); @@ -764,75 +764,76 @@ template struct _storage { if (self.has_value()) { return ::std::invoke(FWD(fn)); } - return result_t(unexpect, _storage::_error(FWD(self))); + return result_t(unexpect, _expected_base::_error(FWD(self))); } template static constexpr auto _or_else(Self &&self, Fn &&fn) // - noexcept(::std::is_nothrow_invocable_v - && ::std::is_nothrow_constructible_v) - requires(not ::std::is_void_v && ::std::is_invocable_v - && ::std::is_constructible_v) + noexcept(::std::is_nothrow_invocable_v + && ::std::is_nothrow_constructible_v) + requires(not ::std::is_void_v && ::std::is_invocable_v + && ::std::is_constructible_v) { - using result_t = ::std::remove_cvref_t<::std::invoke_result_t>; + using result_t = ::std::remove_cvref_t<::std::invoke_result_t>; static_assert(Policy::template is_specialization); static_assert(::std::is_same_v::value_type>); if (self.has_value()) { - return result_t(::std::in_place, _storage::_value(FWD(self))); + return result_t(::std::in_place, _expected_base::_value(FWD(self))); } - return ::std::invoke(FWD(fn), _storage::_error(FWD(self))); + return ::std::invoke(FWD(fn), _expected_base::_error(FWD(self))); } template static constexpr auto _or_else(Self &&self, Fn &&fn) // - noexcept(::std::is_nothrow_invocable_v) - requires(::std::is_void_v && ::std::is_invocable_v) + noexcept(::std::is_nothrow_invocable_v) + requires(::std::is_void_v && ::std::is_invocable_v) { - using result_t = ::std::remove_cvref_t<::std::invoke_result_t>; + using result_t = ::std::remove_cvref_t<::std::invoke_result_t>; static_assert(Policy::template is_specialization); static_assert(::std::is_same_v::value_type>); if (self.has_value()) { return result_t(::std::in_place); } - return ::std::invoke(FWD(fn), _storage::_error(FWD(self))); + return ::std::invoke(FWD(fn), _expected_base::_error(FWD(self))); } template static constexpr auto _transform(Self &&self, Fn &&fn) // - noexcept(::std::is_nothrow_invocable_v - && ::std::is_nothrow_constructible_v - && (::std::is_void_v<::std::invoke_result_t> + noexcept(::std::is_nothrow_invocable_v + && ::std::is_nothrow_constructible_v + && (::std::is_void_v<::std::invoke_result_t> || ::std::is_nothrow_constructible_v< - ::std::remove_cv_t<::std::invoke_result_t>, - ::std::invoke_result_t>)) - requires(not ::std::is_void_v && ::std::is_invocable_v - && ::std::is_constructible_v) + ::std::remove_cv_t<::std::invoke_result_t>, + ::std::invoke_result_t>)) + requires(not ::std::is_void_v && ::std::is_invocable_v + && ::std::is_constructible_v) { - using value_t = ::std::remove_cv_t<::std::invoke_result_t>; + using value_t = ::std::remove_cv_t<::std::invoke_result_t>; static_assert(detail::_is_valid_expected); using result_t = typename Policy::template type; if (self.has_value()) { if constexpr (not ::std::is_void_v) { static_assert( - ::std::is_constructible_v>); - return result_t(::std::in_place, ::std::invoke(FWD(fn), _storage::_value(FWD(self)))); + ::std::is_constructible_v>); + return result_t(::std::in_place, ::std::invoke(FWD(fn), _expected_base::_value(FWD(self)))); } else { - ::std::invoke(FWD(fn), _storage::_value(FWD(self))); + ::std::invoke(FWD(fn), _expected_base::_value(FWD(self))); return result_t(::std::in_place); } } - return result_t(unexpect, _storage::_error(FWD(self))); + return result_t(unexpect, _expected_base::_error(FWD(self))); } template static constexpr auto _transform(Self &&self, Fn &&fn) // noexcept(::std::is_nothrow_invocable_v - && ::std::is_nothrow_constructible_v + && ::std::is_nothrow_constructible_v && (::std::is_void_v<::std::invoke_result_t> || ::std::is_nothrow_constructible_v<::std::remove_cv_t<::std::invoke_result_t>, ::std::invoke_result_t>)) requires(::std::is_void_v && ::std::is_invocable_v - && ::std::is_constructible_v) + && ::std::is_constructible_v) { using value_t = ::std::remove_cv_t<::std::invoke_result_t>; static_assert(detail::_is_valid_expected); @@ -846,45 +847,45 @@ template struct _storage { return result_t(::std::in_place); } } - return result_t(unexpect, _storage::_error(FWD(self))); + return result_t(unexpect, _expected_base::_error(FWD(self))); } template static constexpr auto _transform_error(Self &&self, Fn &&fn) // - noexcept(::std::is_nothrow_invocable_v - && ::std::is_nothrow_constructible_v + noexcept(::std::is_nothrow_invocable_v + && ::std::is_nothrow_constructible_v && ::std::is_nothrow_constructible_v< - ::std::remove_cv_t<::std::invoke_result_t>, - ::std::invoke_result_t>) - requires(not ::std::is_void_v && ::std::is_invocable_v - && ::std::is_constructible_v) + ::std::remove_cv_t<::std::invoke_result_t>, + ::std::invoke_result_t>) + requires(not ::std::is_void_v && ::std::is_invocable_v + && ::std::is_constructible_v) { - using error_t = ::std::remove_cv_t<::std::invoke_result_t>; + using error_t = ::std::remove_cv_t<::std::invoke_result_t>; static_assert(detail::_is_valid_unexpected); static_assert( - ::std::is_constructible_v>); + ::std::is_constructible_v>); using result_t = typename Policy::template type; if (not self.has_value()) { - return result_t(unexpect, ::std::invoke(FWD(fn), _storage::_error(FWD(self)))); + return result_t(unexpect, ::std::invoke(FWD(fn), _expected_base::_error(FWD(self)))); } - return result_t(::std::in_place, _storage::_value(FWD(self))); + return result_t(::std::in_place, _expected_base::_value(FWD(self))); } template static constexpr auto _transform_error(Self &&self, Fn &&fn) // - noexcept(::std::is_nothrow_invocable_v + noexcept(::std::is_nothrow_invocable_v && ::std::is_nothrow_constructible_v< - ::std::remove_cv_t<::std::invoke_result_t>, - ::std::invoke_result_t>) - requires(::std::is_void_v && ::std::is_invocable_v) + ::std::remove_cv_t<::std::invoke_result_t>, + ::std::invoke_result_t>) + requires(::std::is_void_v && ::std::is_invocable_v) { - using error_t = ::std::remove_cv_t<::std::invoke_result_t>; + using error_t = ::std::remove_cv_t<::std::invoke_result_t>; static_assert(detail::_is_valid_unexpected); static_assert( - ::std::is_constructible_v>); + ::std::is_constructible_v>); using result_t = typename Policy::template type; if (not self.has_value()) { - return result_t(unexpect, ::std::invoke(FWD(fn), _storage::_error(FWD(self)))); + return result_t(unexpect, ::std::invoke(FWD(fn), _expected_base::_error(FWD(self)))); } return result_t(::std::in_place); } @@ -927,7 +928,7 @@ template struct _storage { } // Cross-state swap; lhs holds value, rhs holds error. - static constexpr void _swap_helper(_storage &lhs, _storage &rhs) // + static constexpr void _swap_helper(_expected_base &lhs, _expected_base &rhs) // noexcept(::std::is_nothrow_move_constructible_v && ::std::is_nothrow_move_constructible_v) { if constexpr (::std::is_nothrow_move_constructible_v) { @@ -957,7 +958,7 @@ template struct _storage { rhs.set_ = true; } - constexpr void _swap_with(_storage &rhs) + constexpr void _swap_with(_expected_base &rhs) { if (set_ == rhs.set_) { if (set_) { @@ -1077,13 +1078,13 @@ struct expected_policy { } // namespace detail -template class expected : private detail::_storage { +template class expected : private detail::_expected_base { static_assert(detail::_is_valid_expected); - using _base = detail::_storage; + using _base = detail::_expected_base; - // Allow sibling `_storage` instantiations to downcast into our private base + // Allow sibling `_expected_base` instantiations to downcast into our private base // (needed for the lifted converting ctors and friend operators). - template friend struct detail::_storage; + template friend struct detail::_expected_base; public: using value_type = T; @@ -1250,10 +1251,10 @@ template class expected : private detail::_storage && ::std::is_nothrow_swappable_v && ::std::is_nothrow_move_constructible_v && ::std::is_nothrow_swappable_v) @@ -1264,7 +1265,7 @@ template class expected : private detail::_storage_swap_with(rhs); } - // [expected.object.obs], observers inherited from _storage + // [expected.object.obs], observers inherited from _expected_base using _base::operator*; using _base::operator->; using _base::operator bool; @@ -1392,17 +1393,17 @@ template class expected : private detail::_storage