https://gcc.gnu.org/g:197dec13806ec8d9d43089317884734e6c5d1140
commit r17-2116-g197dec13806ec8d9d43089317884734e6c5d1140 Author: Tomasz Kamiński <[email protected]> Date: Wed Jul 1 10:47:59 2026 +0200 libstdc++: Extract optional<T&> specialization to bits/optional_ref.h. This patch extracts optional<_Tp&> specialization to the new bits/optional_ref.h file. This allows it to be used as return type of exception_ptr_cast (as required by P3981R2) from <exception>, without introducing cyclic dependency. In addition to reference specialization, the definitions of nullopt_t, nullopt, __is_valid_contained_type..., and _Optional_func required for it are moved to this new file. We also forward declare __gnu_cxx::__normal_iterator required for iterator type defintion. To minimize set of dependencies, the following methods remain defined (now out of line) in <optional> header: * value - requires __throw_bad_optional_access * begin/end - requires __normal_iterator * then, or_else, transform, constructor from _Optional_func - depends on invoke * value_or - moved for consistency Furthemore, to avoid introduction of dependency of <concepts>, the requires clause for or_else is changed from invocable<_Fn> to is_invocable_v<_Fn>. The is conforming, as standard specifies the former in Constraints, and user cannot really on subsumption. Finally, the in_place_t (and other tags) are extracted into separate bits/inplace_tags.h header, removing the dependency on bits/utility.h. libstdc++-v3/ChangeLog: * include/Makefile.am (bits/optional_ref.h): Add. * include/Makefile.in: Regenerate. * include/bits/inplace_tags.h: New file. * include/bits/utility.h (std::in_place_t, std::in_place) (std::in_place_type_t, std::in_place_type) (std::in_place_index_t, in_place_index): Move to bits/inplace_tags.h. * include/bits/optional_ref.h: New file. * include/std/optional (std::nullopt_t, std::nullopt) (std::__is_valid_contained_type_for_optional) (std::_Optional_func, std::optional<_Tp&>) (std::__is_optional_ref_v, std::__optional_ref_base): Moved to bits/optional_ref.h. (optional<_Tp&>::begin, optional<_Tp&>::end) (optional<_Tp&>::value, optional<_Tp&>::value_or) (optional<_Tp&>::and_then, optional<_Tp&>::transform) (optional<_Tp&>::optional(_Optional_func<_Fn>, _Value)): Define out of line. (optional<_Tp&>::or_else): Define out of line, and change requires from invocable<_Fn> to is_invocable_v<_Fn>. Reviewed-by: Jonathan Wakely <[email protected]> Signed-off-by: Tomasz Kamiński <[email protected]> Diff: --- libstdc++-v3/include/Makefile.am | 2 + libstdc++-v3/include/Makefile.in | 2 + libstdc++-v3/include/bits/inplace_tags.h | 84 +++++++ libstdc++-v3/include/bits/optional_ref.h | 385 +++++++++++++++++++++++++++++ libstdc++-v3/include/bits/utility.h | 39 +-- libstdc++-v3/include/std/optional | 405 +++++-------------------------- 6 files changed, 541 insertions(+), 376 deletions(-) diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index db2b09180692..3c30aa21d6b5 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -138,6 +138,7 @@ bits_freestanding = \ ${bits_srcdir}/enable_special_members.h \ ${bits_srcdir}/functexcept.h \ ${bits_srcdir}/functional_hash.h \ + ${bits_srcdir}/inplace_tags.h \ ${bits_srcdir}/intcmp.h \ ${bits_srcdir}/invoke.h \ ${bits_srcdir}/iosfwd.h \ @@ -152,6 +153,7 @@ bits_freestanding = \ ${bits_srcdir}/memoryfwd.h \ ${bits_srcdir}/monostate.h \ ${bits_srcdir}/move.h \ + ${bits_srcdir}/optional_ref.h \ ${bits_srcdir}/ostream.h \ ${bits_srcdir}/out_ptr.h \ ${bits_srcdir}/predefined_ops.h \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index c6add0968d92..d081481293ff 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -496,6 +496,7 @@ bits_freestanding = \ ${bits_srcdir}/enable_special_members.h \ ${bits_srcdir}/functexcept.h \ ${bits_srcdir}/functional_hash.h \ + ${bits_srcdir}/inplace_tags.h \ ${bits_srcdir}/intcmp.h \ ${bits_srcdir}/invoke.h \ ${bits_srcdir}/iosfwd.h \ @@ -510,6 +511,7 @@ bits_freestanding = \ ${bits_srcdir}/memoryfwd.h \ ${bits_srcdir}/monostate.h \ ${bits_srcdir}/move.h \ + ${bits_srcdir}/optional_ref.h \ ${bits_srcdir}/ostream.h \ ${bits_srcdir}/out_ptr.h \ ${bits_srcdir}/predefined_ops.h \ diff --git a/libstdc++-v3/include/bits/inplace_tags.h b/libstdc++-v3/include/bits/inplace_tags.h new file mode 100644 index 000000000000..c6c1f762c611 --- /dev/null +++ b/libstdc++-v3/include/bits/inplace_tags.h @@ -0,0 +1,84 @@ +// Tag types for inplace construction. -*- C++ -*- + +// Copyright (C) 2004-2026 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file include/bits/inplace_tags.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{utility} + * + * This file contains the parts of `<utility>` needed by other headers, + * so they don't need to include the whole of `<utility>`. + */ + +#ifndef _GLIBCXX_INPLACE_TAGS_H +#define _GLIBCXX_INPLACE_TAGS_H 1 + +#ifdef _GLIBCXX_SYSHDR +#pragma GCC system_header +#endif + +#if __cplusplus >= 201703L + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + struct in_place_t { + explicit in_place_t() = default; + }; + + inline constexpr in_place_t in_place{}; + + template<typename _Tp> struct in_place_type_t + { + explicit in_place_type_t() = default; + }; + + template<typename _Tp> + inline constexpr in_place_type_t<_Tp> in_place_type{}; + + template<size_t _Idx> struct in_place_index_t + { + explicit in_place_index_t() = default; + }; + + template<size_t _Idx> + inline constexpr in_place_index_t<_Idx> in_place_index{}; + + template<typename> + inline constexpr bool __is_in_place_type_v = false; + + template<typename _Tp> + inline constexpr bool __is_in_place_type_v<in_place_type_t<_Tp>> = true; + + template<typename> + inline constexpr bool __is_in_place_index_v = false; + + template<size_t _Nm> + inline constexpr bool __is_in_place_index_v<in_place_index_t<_Nm>> = true; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // C++17 +#endif /* _GLIBCXX_INPLACE_TAGS_H */ diff --git a/libstdc++-v3/include/bits/optional_ref.h b/libstdc++-v3/include/bits/optional_ref.h new file mode 100644 index 000000000000..69a87410e9fd --- /dev/null +++ b/libstdc++-v3/include/bits/optional_ref.h @@ -0,0 +1,385 @@ +// optional<T&> -*- C++ -*- + +// Copyright (C) 2013-2026 Free Software Foundation, Inc. +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file bits/optional_ref.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{optional} + */ + +#ifndef _GLIBCXX_OPTIONAL_REF +#define _GLIBCXX_OPTIONAL_REF 1 + +#ifdef _GLIBCXX_SYSHDR +#pragma GCC system_header +#endif + +#ifdef __glibcxx_optional // C++ >= 17 + +#include <type_traits> +#include <bits/move.h> +#include <bits/inplace_tags.h> + +namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + template<typename _Iterator, typename _Container> + class __normal_iterator; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace __gnu_cxx + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup utilities + * @{ + */ + + template<typename _Tp> + class optional; + + /// Tag type to disengage optional objects. + struct nullopt_t + { + // Do not user-declare default constructor at all for + // optional_value = {} syntax to work. + // nullopt_t() = delete; + + // Used for constructing nullopt. + enum class _Construct { _Token }; + + // Must be constexpr for nullopt_t to be literal. + explicit constexpr nullopt_t(_Construct) noexcept { } + }; + + /// Tag to disengage optional objects. + inline constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token }; + + template<typename _Fn> struct _Optional_func { _Fn& _M_f; }; + + template<typename _Tp> + inline constexpr bool __is_valid_contained_type_for_optional = + ( +#if __glibcxx_optional >= 202506L + is_lvalue_reference_v<_Tp> || +#endif + (is_object_v<_Tp> && is_destructible_v<_Tp> && !is_array_v<_Tp>) + ) + && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, nullopt_t> + && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, in_place_t>; + +#if __glibcxx_optional >= 202506L // C++26 + template<typename _Tp> + class optional<_Tp&>; + + template<typename _Tp> + constexpr bool __is_optional_ref_v = false; + + template<typename _Tp> + constexpr bool __is_optional_ref_v<optional<_Tp&>> = true; + + template<typename _Tp> + struct __optional_ref_base + {}; + +#ifdef __glibcxx_optional_range_support // >= C++26 + template<typename _Tp> + struct __optional_ref_base<_Tp[]> + {}; + + template<typename _Tp> + requires is_object_v<_Tp> + struct __optional_ref_base<_Tp> + { + using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional<_Tp&>>; + }; +#endif // __glibcxx_optional_range_support + + template<typename _Tp> + class optional<_Tp&> : public __optional_ref_base<_Tp> + { + static_assert(__is_valid_contained_type_for_optional<_Tp&>); + + public: + using value_type = _Tp; + + // Constructors. + constexpr optional() noexcept = default; + constexpr optional(nullopt_t) noexcept : optional() {} + constexpr optional(const optional&) noexcept = default; + + template<typename _Arg> + requires is_constructible_v<_Tp&, _Arg> + && (!reference_constructs_from_temporary_v<_Tp&, _Arg>) + explicit constexpr + optional(in_place_t, _Arg&& __arg) + { + __convert_ref_init_val(std::forward<_Arg>(__arg)); + } + + template<typename _Up> + requires (!is_same_v<remove_cvref_t<_Up>, optional>) + && (!is_same_v<remove_cvref_t<_Up>, in_place_t>) + && is_constructible_v<_Tp&, _Up> + && (!reference_constructs_from_temporary_v<_Tp&, _Up>) + explicit(!is_convertible_v<_Up, _Tp&>) + constexpr + optional(_Up&& __u) + noexcept(is_nothrow_constructible_v<_Tp&, _Up>) + { + __convert_ref_init_val(std::forward<_Up>(__u)); + } + + template<typename _Up> + requires (!is_same_v<remove_cvref_t<_Up>, optional>) + && (!is_same_v<remove_cvref_t<_Up>, in_place_t>) + && is_constructible_v<_Tp&, _Up> + && reference_constructs_from_temporary_v<_Tp&, _Up> + explicit(!is_convertible_v<_Up, _Tp&>) + constexpr + optional(_Up&& __u) = delete; + + // optional<U> & + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, _Up&> + && (!reference_constructs_from_temporary_v<_Tp&, _Up&>) + explicit(!is_convertible_v<_Up&, _Tp&>) + constexpr + optional(optional<_Up>& __rhs) + noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) + { + if (__rhs) + __convert_ref_init_val(__rhs._M_fwd()); + } + + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, _Up&> + && reference_constructs_from_temporary_v<_Tp&, _Up&> + explicit(!is_convertible_v<_Up&, _Tp&>) + constexpr + optional(optional<_Up>& __rhs) = delete; + + // const optional<U>& + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, const _Up&> + && (!reference_constructs_from_temporary_v<_Tp&, const _Up&>) + explicit(!is_convertible_v<const _Up&, _Tp&>) + constexpr + optional(const optional<_Up>& __rhs) + noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) + { + if (__rhs) + __convert_ref_init_val(__rhs._M_fwd()); + } + + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, const _Up&> + && reference_constructs_from_temporary_v<_Tp&, const _Up&> + explicit(!is_convertible_v<const _Up&, _Tp&>) + constexpr + optional(const optional<_Up>& __rhs) = delete; + + // optional<U>&& + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, _Up> + && (!reference_constructs_from_temporary_v<_Tp&, _Up>) + explicit(!is_convertible_v<_Up, _Tp&>) + constexpr + optional(optional<_Up>&& __rhs) + noexcept(is_nothrow_constructible_v<_Tp&, _Up>) + { + if (__rhs) + __convert_ref_init_val(std::move(__rhs)._M_fwd()); + } + + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, _Up> + && reference_constructs_from_temporary_v<_Tp&, _Up> + explicit(!is_convertible_v<_Up, _Tp&>) + constexpr + optional(optional<_Up>&& __rhs) = delete; + + // const optional<U>&& + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, const _Up> + && (!reference_constructs_from_temporary_v<_Tp&, _Up>) + explicit(!is_convertible_v<const _Up, _Tp&>) + constexpr + optional(const optional<_Up>&& __rhs) + noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) + { + if (__rhs) + __convert_ref_init_val(std::move(__rhs)._M_fwd()); + } + + template<typename _Up> + requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) + && (!is_same_v<_Tp&, _Up>) + && is_constructible_v<_Tp&, const _Up> + && reference_constructs_from_temporary_v<_Tp&, const _Up> + explicit(!is_convertible_v<const _Up, _Tp&>) + constexpr + optional(const optional<_Up>&& __rhs) = delete; + + constexpr ~optional() = default; + + // Assignment. + constexpr optional& operator=(nullopt_t) noexcept + { + _M_val = nullptr; + return *this; + } + + constexpr optional& operator=(const optional&) noexcept = default; + + template<typename _Up> + requires is_constructible_v<_Tp&, _Up> + && (!reference_constructs_from_temporary_v<_Tp&, _Up>) + constexpr _Tp& + emplace(_Up&& __u) + noexcept(is_nothrow_constructible_v<_Tp&, _Up>) + { + __convert_ref_init_val(std::forward<_Up>(__u)); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4300. Missing Returns: element in optional<T&>::emplace + return *_M_val; + } + + // Swap. + constexpr void swap(optional& __rhs) noexcept + { std::swap(_M_val, __rhs._M_val); } + +#ifdef __glibcxx_optional_range_support // >= C++26 + // Iterator support. + constexpr auto begin() const noexcept + requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>); + + constexpr auto end() const noexcept + requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>); +#endif // __glibcxx_optional_range_support + + // Observers. + constexpr _Tp* operator->() const noexcept + { + __glibcxx_assert(_M_val); // hardened precondition + return _M_val; + } + + constexpr _Tp& operator*() const noexcept + { + __glibcxx_assert(_M_val); // hardened precondition + return *_M_val; + } + + constexpr explicit operator bool() const noexcept + { + return _M_val; + } + + constexpr bool has_value() const noexcept + { + return _M_val; + } + + constexpr _Tp& value() const; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4304. std::optional<NonReturnable&> is ill-formed due to value_or + template<typename _Up = remove_cv_t<_Tp>> + requires is_object_v<_Tp> && (!is_array_v<_Tp>) + constexpr decay_t<_Tp> + value_or(_Up&& __u) const; + + // Monadic operations. + template<typename _Fn> + constexpr auto + and_then(_Fn&& __f) const; + + template<typename _Fn> + constexpr + optional<remove_cv_t<invoke_result_t<_Fn, _Tp&>>> + transform(_Fn&& __f) const; + + template<typename _Fn> + requires is_invocable_v<_Fn> + constexpr + optional + or_else(_Fn&& __f) const; + + // Modifiers. + constexpr void reset() noexcept + { + _M_val = nullptr; + } + + private: + _Tp *_M_val = nullptr; + + [[__gnu__::__always_inline__]] + constexpr _Tp& + _M_fwd() const noexcept + { return *_M_val; } + + template<typename _Up> friend class optional; + + template<typename _Up> + constexpr + void + __convert_ref_init_val(_Up&& __u) + noexcept + { + _Tp& __r(std::forward<_Up>(__u)); + _M_val = std::addressof(__r); + } + + template<typename _Fn, typename _Value> + explicit constexpr + optional(_Optional_func<_Fn> __f, _Value&& __v); + }; +#endif // __glibcxx_optional >= 202506L + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // __glibcxx_optional + +#endif // _GLIBCXX_OPTIONAL_REF diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h index 320dd507b43d..f3e956f33f9f 100644 --- a/libstdc++-v3/include/bits/utility.h +++ b/libstdc++-v3/include/bits/utility.h @@ -41,6 +41,7 @@ #include <type_traits> #include <bits/move.h> +#include <bits/inplace_tags.h> #ifdef __glibcxx_constant_wrapper // C++ >= 26 # include <bits/invoke.h> #endif @@ -549,44 +550,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif // __integer_pack #endif // __cpp_structured_bindings >= 202411L -#if __cplusplus >= 201703L - - struct in_place_t { - explicit in_place_t() = default; - }; - - inline constexpr in_place_t in_place{}; - - template<typename _Tp> struct in_place_type_t - { - explicit in_place_type_t() = default; - }; - - template<typename _Tp> - inline constexpr in_place_type_t<_Tp> in_place_type{}; - - template<size_t _Idx> struct in_place_index_t - { - explicit in_place_index_t() = default; - }; - - template<size_t _Idx> - inline constexpr in_place_index_t<_Idx> in_place_index{}; - - template<typename> - inline constexpr bool __is_in_place_type_v = false; - - template<typename _Tp> - inline constexpr bool __is_in_place_type_v<in_place_type_t<_Tp>> = true; - - template<typename> - inline constexpr bool __is_in_place_index_v = false; - - template<size_t _Nm> - inline constexpr bool __is_in_place_index_v<in_place_index_t<_Nm>> = true; - -#endif // C++17 - #if _GLIBCXX_USE_BUILTIN_TRAIT(__type_pack_element) template<size_t _Np, typename... _Types> struct _Nth_type diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index 221beb2446d6..d6fd33e8c2e1 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -51,6 +51,7 @@ #include <bits/enable_special_members.h> #include <bits/exception_defines.h> #include <bits/functional_hash.h> +#include <bits/optional_ref.h> // nullopt_t, optional<_Tp&> #include <bits/stl_construct.h> // _Construct #include <bits/utility.h> // in_place_t #if __cplusplus > 201703L @@ -77,28 +78,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @{ */ - template<typename _Tp> - class optional; - - /// Tag type to disengage optional objects. - struct nullopt_t - { - // Do not user-declare default constructor at all for - // optional_value = {} syntax to work. - // nullopt_t() = delete; - - // Used for constructing nullopt. - enum class _Construct { _Token }; - - // Must be constexpr for nullopt_t to be literal. - explicit constexpr nullopt_t(_Construct) noexcept { } - }; - - /// Tag to disengage optional objects. - inline constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token }; - - template<typename _Fn> struct _Optional_func { _Fn& _M_f; }; - /** * @brief Exception class thrown when a disengaged optional object is * dereferenced. @@ -795,17 +774,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION # define _GLIBCXX_USE_CONSTRAINTS_FOR_OPTIONAL 1 #endif - template<typename _Tp> - inline constexpr bool __is_valid_contained_type_for_optional = - ( -#if __cpp_lib_optional >= 202506L - is_lvalue_reference_v<_Tp> || -#endif - (is_object_v<_Tp> && is_destructible_v<_Tp> && !is_array_v<_Tp>) - ) - && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, nullopt_t> - && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, in_place_t>; - /** * @brief Class template for optional values. */ @@ -1505,334 +1473,95 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #if __cpp_lib_optional >= 202506L // C++26 +#ifdef __cpp_lib_optional_range_support template<typename _Tp> - class optional<_Tp&>; - - template<typename _Tp> - constexpr bool __is_optional_ref_v = false; - - template<typename _Tp> - constexpr bool __is_optional_ref_v<optional<_Tp&>> = true; - - template<typename _Tp> - struct __optional_ref_base - {}; - -#ifdef __cpp_lib_optional_range_support // >= C++26 - template<typename _Tp> - struct __optional_ref_base<_Tp[]> - {}; + constexpr auto + optional<_Tp&>::begin() const noexcept + requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>) + { return __gnu_cxx::__normal_iterator<_Tp*, optional>(_M_val); } template<typename _Tp> - requires is_object_v<_Tp> - struct __optional_ref_base<_Tp> - { - using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional<_Tp&>>; - }; + constexpr auto + optional<_Tp&>::end() const noexcept + requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>) + { return begin() + has_value(); } #endif // __cpp_lib_optional_range_support template<typename _Tp> - class optional<_Tp&> : public __optional_ref_base<_Tp> + constexpr _Tp& + optional<_Tp&>::value() const { - static_assert(__is_valid_contained_type_for_optional<_Tp&>); - - public: - using value_type = _Tp; - - // Constructors. - constexpr optional() noexcept = default; - constexpr optional(nullopt_t) noexcept : optional() {} - constexpr optional(const optional&) noexcept = default; - - template<typename _Arg> - requires is_constructible_v<_Tp&, _Arg> - && (!reference_constructs_from_temporary_v<_Tp&, _Arg>) - explicit constexpr - optional(in_place_t, _Arg&& __arg) - { - __convert_ref_init_val(std::forward<_Arg>(__arg)); - } - - template<typename _Up> - requires (!is_same_v<remove_cvref_t<_Up>, optional>) - && (!is_same_v<remove_cvref_t<_Up>, in_place_t>) - && is_constructible_v<_Tp&, _Up> - && (!reference_constructs_from_temporary_v<_Tp&, _Up>) - explicit(!is_convertible_v<_Up, _Tp&>) - constexpr - optional(_Up&& __u) - noexcept(is_nothrow_constructible_v<_Tp&, _Up>) - { - __convert_ref_init_val(std::forward<_Up>(__u)); - } - - template<typename _Up> - requires (!is_same_v<remove_cvref_t<_Up>, optional>) - && (!is_same_v<remove_cvref_t<_Up>, in_place_t>) - && is_constructible_v<_Tp&, _Up> - && reference_constructs_from_temporary_v<_Tp&, _Up> - explicit(!is_convertible_v<_Up, _Tp&>) - constexpr - optional(_Up&& __u) = delete; - - // optional<U> & - template<typename _Up> - requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) - && (!is_same_v<_Tp&, _Up>) - && is_constructible_v<_Tp&, _Up&> - && (!reference_constructs_from_temporary_v<_Tp&, _Up&>) - explicit(!is_convertible_v<_Up&, _Tp&>) - constexpr - optional(optional<_Up>& __rhs) - noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) - { - if (__rhs) - __convert_ref_init_val(__rhs._M_fwd()); - } - - template<typename _Up> - requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) - && (!is_same_v<_Tp&, _Up>) - && is_constructible_v<_Tp&, _Up&> - && reference_constructs_from_temporary_v<_Tp&, _Up&> - explicit(!is_convertible_v<_Up&, _Tp&>) - constexpr - optional(optional<_Up>& __rhs) = delete; - - // const optional<U>& - template<typename _Up> - requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) - && (!is_same_v<_Tp&, _Up>) - && is_constructible_v<_Tp&, const _Up&> - && (!reference_constructs_from_temporary_v<_Tp&, const _Up&>) - explicit(!is_convertible_v<const _Up&, _Tp&>) - constexpr - optional(const optional<_Up>& __rhs) - noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) - { - if (__rhs) - __convert_ref_init_val(__rhs._M_fwd()); - } - - template<typename _Up> - requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) - && (!is_same_v<_Tp&, _Up>) - && is_constructible_v<_Tp&, const _Up&> - && reference_constructs_from_temporary_v<_Tp&, const _Up&> - explicit(!is_convertible_v<const _Up&, _Tp&>) - constexpr - optional(const optional<_Up>& __rhs) = delete; - - // optional<U>&& - template<typename _Up> - requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) - && (!is_same_v<_Tp&, _Up>) - && is_constructible_v<_Tp&, _Up> - && (!reference_constructs_from_temporary_v<_Tp&, _Up>) - explicit(!is_convertible_v<_Up, _Tp&>) - constexpr - optional(optional<_Up>&& __rhs) - noexcept(is_nothrow_constructible_v<_Tp&, _Up>) - { - if (__rhs) - __convert_ref_init_val(std::move(__rhs)._M_fwd()); - } - - template<typename _Up> - requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) - && (!is_same_v<_Tp&, _Up>) - && is_constructible_v<_Tp&, _Up> - && reference_constructs_from_temporary_v<_Tp&, _Up> - explicit(!is_convertible_v<_Up, _Tp&>) - constexpr - optional(optional<_Up>&& __rhs) = delete; - - // const optional<U>&& - template<typename _Up> - requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) - && (!is_same_v<_Tp&, _Up>) - && is_constructible_v<_Tp&, const _Up> - && (!reference_constructs_from_temporary_v<_Tp&, _Up>) - explicit(!is_convertible_v<const _Up, _Tp&>) - constexpr - optional(const optional<_Up>&& __rhs) - noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) - { - if (__rhs) - __convert_ref_init_val(std::move(__rhs)._M_fwd()); - } - - template<typename _Up> - requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>) - && (!is_same_v<_Tp&, _Up>) - && is_constructible_v<_Tp&, const _Up> - && reference_constructs_from_temporary_v<_Tp&, const _Up> - explicit(!is_convertible_v<const _Up, _Tp&>) - constexpr - optional(const optional<_Up>&& __rhs) = delete; - - constexpr ~optional() = default; + if (_M_val) + return *_M_val; + __throw_bad_optional_access(); + } - // Assignment. - constexpr optional& operator=(nullopt_t) noexcept + template<typename _Tp> + template<typename _Up> + requires is_object_v<_Tp> && (!is_array_v<_Tp>) + constexpr decay_t<_Tp> + optional<_Tp&>::value_or(_Up&& __u) const { - _M_val = nullptr; - return *this; - } - - constexpr optional& operator=(const optional&) noexcept = default; - - template<typename _Up> - requires is_constructible_v<_Tp&, _Up> - && (!reference_constructs_from_temporary_v<_Tp&, _Up>) - constexpr _Tp& - emplace(_Up&& __u) - noexcept(is_nothrow_constructible_v<_Tp&, _Up>) - { - __convert_ref_init_val(std::forward<_Up>(__u)); - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 4300. Missing Returns: element in optional<T&>::emplace + using _Xp = remove_cv_t<_Tp>; + static_assert(is_convertible_v<_Tp&, _Xp>); + static_assert(is_convertible_v<_Up, _Xp>); + if (_M_val) return *_M_val; - } - - // Swap. - constexpr void swap(optional& __rhs) noexcept - { std::swap(_M_val, __rhs._M_val); } - -#ifdef __cpp_lib_optional_range_support // >= C++26 - // Iterator support. - constexpr auto begin() const noexcept - requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>) - { return __gnu_cxx::__normal_iterator<_Tp*, optional>(_M_val); } - - constexpr auto end() const noexcept - requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>) - { return begin() + has_value(); } -#endif // __cpp_lib_optional_range_support - - // Observers. - constexpr _Tp* operator->() const noexcept - { - __glibcxx_assert(_M_val); // hardened precondition - return _M_val; - } - - constexpr _Tp& operator*() const noexcept - { - __glibcxx_assert(_M_val); // hardened precondition - return *_M_val; + return std::forward<_Up>(__u); } - constexpr explicit operator bool() const noexcept + template<typename _Tp> + template<typename _Fn> + constexpr auto + optional<_Tp&>::and_then(_Fn&& __f) const { - return _M_val; + using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp&>>; + static_assert(__is_optional_v<_Up>, + "the function passed to std::optional<T&>::and_then " + "must return a std::optional"); + if (has_value()) + return std::__invoke(std::forward<_Fn>(__f), *_M_val); + else + return _Up(); } - constexpr bool has_value() const noexcept + template<typename _Tp> + template<typename _Fn> + constexpr optional<remove_cv_t<invoke_result_t<_Fn, _Tp&>>> + optional<_Tp&>::transform(_Fn&& __f) const { - return _M_val; + using _Up = remove_cv_t<invoke_result_t<_Fn, _Tp&>>; + if (has_value()) + return optional<_Up>(_Optional_func<_Fn>{__f}, *_M_val); + else + return optional<_Up>(); } - constexpr _Tp& value() const + template<typename _Tp> + template<typename _Fn> + requires is_invocable_v<_Fn> + constexpr optional<_Tp&> + optional<_Tp&>::or_else(_Fn&& __f) const { - if (_M_val) - return *_M_val; - __throw_bad_optional_access(); + static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Fn>>, optional>, + "the function passed to std::optional<T&>::or_else " + "must return a std::optional<T&>"); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4367. Improve optional<T&>::or_else + if (has_value()) + return *this; + else + return std::forward<_Fn>(__f)(); } - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 4304. std::optional<NonReturnable&> is ill-formed due to value_or - template<typename _Up = remove_cv_t<_Tp>> - requires is_object_v<_Tp> && (!is_array_v<_Tp>) - constexpr decay_t<_Tp> - value_or(_Up&& __u) const - { - using _Xp = remove_cv_t<_Tp>; - static_assert(is_convertible_v<_Tp&, _Xp>); - static_assert(is_convertible_v<_Up, _Xp>); - if (_M_val) - return *_M_val; - return std::forward<_Up>(__u); - } - - // Monadic operations. - template<typename _Fn> - constexpr auto - and_then(_Fn&& __f) const - { - using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp&>>; - static_assert(__is_optional_v<_Up>, - "the function passed to std::optional<T&>::and_then " - "must return a std::optional"); - if (has_value()) - return std::__invoke(std::forward<_Fn>(__f), *_M_val); - else - return _Up(); - } - - template<typename _Fn> - constexpr - optional<remove_cv_t<invoke_result_t<_Fn, _Tp&>>> - transform(_Fn&& __f) const - { - using _Up = remove_cv_t<invoke_result_t<_Fn, _Tp&>>; - if (has_value()) - return optional<_Up>(_Optional_func<_Fn>{__f}, *_M_val); - else - return optional<_Up>(); - } - - template<typename _Fn> - requires invocable<_Fn> - constexpr - optional - or_else(_Fn&& __f) const - { - static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Fn>>, optional>, - "the function passed to std::optional<T&>::or_else " - "must return a std::optional<T&>"); - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 4367. Improve optional<T&>::or_else - if (has_value()) - return *this; - else - return std::forward<_Fn>(__f)(); - } - - // Modifiers. - constexpr void reset() noexcept + template<typename _Tp> + template<typename _Fn, typename _Value> + constexpr + optional<_Tp&>::optional(_Optional_func<_Fn> __f, _Value&& __v) { - _M_val = nullptr; + _Tp& __r = std::__invoke(std::forward<_Fn>(__f._M_f), std::forward<_Value>(__v)); + _M_val = std::addressof(__r); } - - private: - _Tp *_M_val = nullptr; - - [[__gnu__::__always_inline__]] - constexpr _Tp& - _M_fwd() const noexcept - { return *_M_val; } - - template<typename _Up> friend class optional; - - template<typename _Up> - constexpr - void - __convert_ref_init_val(_Up&& __u) - noexcept - { - _Tp& __r(std::forward<_Up>(__u)); - _M_val = std::addressof(__r); - } - - template<typename _Fn, typename _Value> - explicit constexpr - optional(_Optional_func<_Fn> __f, _Value&& __v) - { - _Tp& __r = std::__invoke(std::forward<_Fn>(__f._M_f), std::forward<_Value>(__v)); - _M_val = std::addressof(__r); - } - }; #endif // __cpp_lib_optional >= 202506L template<typename _Tp>
