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 bist/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>.
---
Testing on x86_64-linux. All test passed locally.
OK for trunk when exteded suite happens?
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 | 389 ++++++++++++++++++++++
libstdc++-v3/include/bits/utility.h | 39 +--
libstdc++-v3/include/std/optional | 405 ++++-------------------
6 files changed, 545 insertions(+), 376 deletions(-)
create mode 100644 libstdc++-v3/include/bits/inplace_tags.h
create mode 100644 libstdc++-v3/include/bits/optional_ref.h
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index f91a93ae4aa..262ba42950b 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 611ef30c6cd..0d97a5acdb2 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 00000000000..c6c1f762c61
--- /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 00000000000..e018a4199e9
--- /dev/null
+++ b/libstdc++-v3/include/bits/optional_ref.h
@@ -0,0 +1,389 @@
+// 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 include/optional
+ * This is a tandard C++ Library header.
+ */
+
+/** @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 320dd507b43..f3e956f33f9 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 221beb2446d..d6fd33e8c2e 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>
--
2.54.0