[PATCH 1/2] libstdc++: Extract optional<T&> specialization to bits/optional_ref.h.
Jonathan Wakely
jwakely@redhat.com
Fri Jul 3 11:44:27 GMT 2026
On Thu, 02 Jul 2026 at 14:22 +0200, Tomasz Kamiński wrote:
>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.
bist -> bits
>
>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.
No it isn't :-)
This comment block should be removed, the @file block below is
correct.
OK with that change
>+ */
>+
>+/** @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
>
>
More information about the Libstdc++
mailing list