1// <experimental/propagate_const> -*- C++ -*-
3// Copyright (C) 2015-2023 Free Software Foundation, Inc.
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
25/** @file experimental/propagate_const
26 * This is a TS C++ Library header.
30#ifndef _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST
31#define _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST 1
33#pragma GCC system_header
35#include <bits/requires_hosted.h> // experimental is currently omitted
37#if __cplusplus >= 201402L
40#include <bits/functional_hash.h>
42#include <bits/stl_function.h>
43#include <experimental/bits/lfts_config.h>
45namespace std _GLIBCXX_VISIBILITY(default)
47_GLIBCXX_BEGIN_NAMESPACE_VERSION
51inline namespace fundamentals_v2
53 template<typename _Tp>
54 using __propagate_const_elem_type
55 = remove_reference_t<decltype(*std::declval<_Tp&>())>;
57 template<typename _Tp,
58 typename _Elem = __propagate_const_elem_type<_Tp>,
59 bool = is_convertible<const _Tp, const _Elem*>::value>
60 struct __propagate_const_conversion_c
63 template<typename _Tp, typename _Elem>
64 struct __propagate_const_conversion_c<_Tp, _Elem, true>
66 constexpr operator const _Elem*() const;
69 template<typename _Tp,
70 typename _Elem = __propagate_const_elem_type<_Tp>,
71 bool = is_convertible<_Tp, _Elem*>::value>
72 struct __propagate_const_conversion_nc
75 template<typename _Tp, typename _Elem>
76 struct __propagate_const_conversion_nc<_Tp, _Elem, true>
78 constexpr operator _Elem*();
81 // Base class of propagate_const<T> when T is a class type.
82 template <typename _Tp>
83 struct __propagate_const_conversions
84 : __propagate_const_conversion_c<_Tp>, __propagate_const_conversion_nc<_Tp>
87 // Base class of propagate_const<T> when T is a pointer type.
88 template<typename _Tp>
89 struct __propagate_const_conversions<_Tp*>
91 constexpr operator const _Tp*() const noexcept;
92 constexpr operator _Tp*() noexcept;
96 * @defgroup propagate_const Const-propagating wrapper
99 * A const-propagating wrapper that propagates const to pointer-like members,
100 * as described in n4388 "A Proposal to Add a Const-Propagating Wrapper
101 * to the Standard Library".
106 /// Const-propagating wrapper.
107 template <typename _Tp>
108 class propagate_const : public __propagate_const_conversions<_Tp>
111 using element_type = __propagate_const_elem_type<_Tp>;
114 template <typename _Up>
115 struct __is_propagate_const : false_type
118 template <typename _Up>
119 struct __is_propagate_const<propagate_const<_Up>> : true_type
122 template <typename _Up>
123 friend constexpr const _Up&
124 get_underlying(const propagate_const<_Up>& __pt) noexcept;
125 template <typename _Up>
126 friend constexpr _Up&
127 get_underlying(propagate_const<_Up>& __pt) noexcept;
129 template <typename _Up>
130 static constexpr element_type*
131 __to_raw_pointer(_Up* __u)
134 template <typename _Up>
135 static constexpr element_type*
136 __to_raw_pointer(_Up& __u)
137 { return __u.get(); }
139 template <typename _Up>
140 static constexpr const element_type*
141 __to_raw_pointer(const _Up* __u)
144 template <typename _Up>
145 static constexpr const element_type*
146 __to_raw_pointer(const _Up& __u)
147 { return __u.get(); }
150 static_assert(__and_<is_object<typename remove_pointer<_Tp>::type>,
151 __not_<is_array<_Tp>>,
152 __or_<is_class<_Tp>, is_pointer<_Tp>>>::value,
153 "propagate_const requires a class or a pointer to an"
156 // [propagate_const.ctor], constructors
157 constexpr propagate_const() = default;
158 propagate_const(const propagate_const& __p) = delete;
159 constexpr propagate_const(propagate_const&& __p) = default;
161 template <typename _Up, typename
162 enable_if<__and_<is_constructible<_Tp, _Up&&>,
163 is_convertible<_Up&&, _Tp>>::value, bool
165 constexpr propagate_const(propagate_const<_Up>&& __pu)
166 : _M_t(std::move(get_underlying(__pu)))
169 template <typename _Up, typename
170 enable_if<__and_<is_constructible<_Tp, _Up&&>,
171 __not_<is_convertible<_Up&&, _Tp>>>::value,
173 constexpr explicit propagate_const(propagate_const<_Up>&& __pu)
174 : _M_t(std::move(get_underlying(__pu)))
177 template <typename _Up, typename
178 enable_if<__and_<is_constructible<_Tp, _Up&&>,
179 is_convertible<_Up&&, _Tp>,
180 __not_<__is_propagate_const<
181 typename decay<_Up>::type>>
182 >::value, bool>::type=true>
183 constexpr propagate_const(_Up&& __u)
184 : _M_t(std::forward<_Up>(__u))
187 template <typename _Up, typename
188 enable_if<__and_<is_constructible<_Tp, _Up&&>,
189 __not_<is_convertible<_Up&&, _Tp>>,
190 __not_<__is_propagate_const<
191 typename decay<_Up>::type>>
192 >::value, bool>::type=false>
193 constexpr explicit propagate_const(_Up&& __u)
194 : _M_t(std::forward<_Up>(__u))
197 // [propagate_const.assignment], assignment
198 propagate_const& operator=(const propagate_const& __p) = delete;
199 constexpr propagate_const& operator=(propagate_const&& __p) = default;
201 template <typename _Up, typename =
202 typename enable_if<is_convertible<_Up&&, _Tp>::value>::type>
203 constexpr propagate_const& operator=(propagate_const<_Up>&& __pu)
205 _M_t = std::move(get_underlying(__pu));
209 template <typename _Up, typename =
210 typename enable_if<__and_<is_convertible<_Up&&, _Tp>,
211 __not_<__is_propagate_const<
212 typename decay<_Up>::type>>
214 constexpr propagate_const& operator=(_Up&& __u)
216 _M_t = std::forward<_Up>(__u);
220 // [propagate_const.const_observers], const observers
221 explicit constexpr operator bool() const
226 constexpr const element_type* operator->() const
231 constexpr const element_type& operator*() const
236 constexpr const element_type* get() const
238 return __to_raw_pointer(_M_t);
241 // [propagate_const.non_const_observers], non-const observers
242 constexpr element_type* operator->()
247 constexpr element_type& operator*()
252 constexpr element_type* get()
254 return __to_raw_pointer(_M_t);
257 // [propagate_const.modifiers], modifiers
259 swap(propagate_const& __pt) noexcept(__is_nothrow_swappable<_Tp>::value)
262 swap(_M_t, get_underlying(__pt));
269 // [propagate_const.relational], relational operators
270 template <typename _Tp>
272 operator==(const propagate_const<_Tp>& __pt, nullptr_t)
274 return get_underlying(__pt) == nullptr;
277 template <typename _Tp>
279 operator==(nullptr_t, const propagate_const<_Tp>& __pu)
281 return nullptr == get_underlying(__pu);
284 template <typename _Tp>
286 operator!=(const propagate_const<_Tp>& __pt, nullptr_t)
288 return get_underlying(__pt) != nullptr;
291 template <typename _Tp>
292 constexpr bool operator!=(nullptr_t, const propagate_const<_Tp>& __pu)
294 return nullptr != get_underlying(__pu);
297 template <typename _Tp, typename _Up>
299 operator==(const propagate_const<_Tp>& __pt,
300 const propagate_const<_Up>& __pu)
302 return get_underlying(__pt) == get_underlying(__pu);
305 template <typename _Tp, typename _Up>
307 operator!=(const propagate_const<_Tp>& __pt,
308 const propagate_const<_Up>& __pu)
310 return get_underlying(__pt) != get_underlying(__pu);
313 template <typename _Tp, typename _Up>
315 operator<(const propagate_const<_Tp>& __pt,
316 const propagate_const<_Up>& __pu)
318 return get_underlying(__pt) < get_underlying(__pu);
321 template <typename _Tp, typename _Up>
323 operator>(const propagate_const<_Tp>& __pt,
324 const propagate_const<_Up>& __pu)
326 return get_underlying(__pt) > get_underlying(__pu);
329 template <typename _Tp, typename _Up>
331 operator<=(const propagate_const<_Tp>& __pt,
332 const propagate_const<_Up>& __pu)
334 return get_underlying(__pt) <= get_underlying(__pu);
337 template <typename _Tp, typename _Up>
339 operator>=(const propagate_const<_Tp>& __pt,
340 const propagate_const<_Up>& __pu)
342 return get_underlying(__pt) >= get_underlying(__pu);
345 template <typename _Tp, typename _Up>
347 operator==(const propagate_const<_Tp>& __pt, const _Up& __u)
349 return get_underlying(__pt) == __u;
352 template <typename _Tp, typename _Up>
354 operator!=(const propagate_const<_Tp>& __pt, const _Up& __u)
356 return get_underlying(__pt) != __u;
359 template <typename _Tp, typename _Up>
361 operator<(const propagate_const<_Tp>& __pt, const _Up& __u)
363 return get_underlying(__pt) < __u;
366 template <typename _Tp, typename _Up>
368 operator>(const propagate_const<_Tp>& __pt, const _Up& __u)
370 return get_underlying(__pt) > __u;
373 template <typename _Tp, typename _Up>
375 operator<=(const propagate_const<_Tp>& __pt, const _Up& __u)
377 return get_underlying(__pt) <= __u;
380 template <typename _Tp, typename _Up>
382 operator>=(const propagate_const<_Tp>& __pt, const _Up& __u)
384 return get_underlying(__pt) >= __u;
387 template <typename _Tp, typename _Up>
389 operator==(const _Tp& __t, const propagate_const<_Up>& __pu)
391 return __t == get_underlying(__pu);
394 template <typename _Tp, typename _Up>
396 operator!=(const _Tp& __t, const propagate_const<_Up>& __pu)
398 return __t != get_underlying(__pu);
401 template <typename _Tp, typename _Up>
403 operator<(const _Tp& __t, const propagate_const<_Up>& __pu)
405 return __t < get_underlying(__pu);
408 template <typename _Tp, typename _Up>
410 operator>(const _Tp& __t, const propagate_const<_Up>& __pu)
412 return __t > get_underlying(__pu);
415 template <typename _Tp, typename _Up>
417 operator<=(const _Tp& __t, const propagate_const<_Up>& __pu)
419 return __t <= get_underlying(__pu);
422 template <typename _Tp, typename _Up>
424 operator>=(const _Tp& __t, const propagate_const<_Up>& __pu)
426 return __t >= get_underlying(__pu);
429 // [propagate_const.algorithms], specialized algorithms
430 // _GLIBCXX_RESOLVE_LIB_DEFECTS
431 // 3413. propagate_const's swap [...] needs to be constrained and use a trait
432 template <typename _Tp>
433 constexpr enable_if_t<__is_swappable<_Tp>::value, void>
434 swap(propagate_const<_Tp>& __pt, propagate_const<_Tp>& __pt2)
435 noexcept(__is_nothrow_swappable<_Tp>::value)
440 // [propagate_const.underlying], underlying pointer access
441 template <typename _Tp>
443 get_underlying(const propagate_const<_Tp>& __pt) noexcept
448 template <typename _Tp>
450 get_underlying(propagate_const<_Tp>& __pt) noexcept
455 template<typename _Tp>
457 __propagate_const_conversions<_Tp*>::operator const _Tp*() const noexcept
458 { return static_cast<const propagate_const<_Tp*>*>(this)->get(); }
460 template<typename _Tp>
462 __propagate_const_conversions<_Tp*>::operator _Tp*() noexcept
463 { return static_cast<propagate_const<_Tp*>*>(this)->get(); }
465 template<typename _Tp, typename _Elem>
467 __propagate_const_conversion_c<_Tp, _Elem, true>::
468 operator const _Elem*() const
469 { return static_cast<const propagate_const<_Tp>*>(this)->get(); }
471 template<typename _Tp, typename _Elem>
473 __propagate_const_conversion_nc<_Tp, _Elem, true>::
475 { return static_cast<propagate_const<_Tp>*>(this)->get(); }
477 /// @} group propagate_const
478} // namespace fundamentals_v2
479} // namespace experimental
481// [propagate_const.hash], hash support
482 template <typename _Tp>
483 struct hash<experimental::propagate_const<_Tp>>
485 using result_type = size_t;
486 using argument_type = experimental::propagate_const<_Tp>;
489 operator()(const experimental::propagate_const<_Tp>& __t) const
490 noexcept(noexcept(hash<_Tp>{}(get_underlying(__t))))
492 return hash<_Tp>{}(get_underlying(__t));
496 // [propagate_const.comparison_function_objects], comparison function objects
497 template <typename _Tp>
498 struct equal_to<experimental::propagate_const<_Tp>>
501 operator()(const experimental::propagate_const<_Tp>& __x,
502 const experimental::propagate_const<_Tp>& __y) const
504 return equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y));
507 typedef experimental::propagate_const<_Tp> first_argument_type;
508 typedef experimental::propagate_const<_Tp> second_argument_type;
509 typedef bool result_type;
512 template <typename _Tp>
513 struct not_equal_to<experimental::propagate_const<_Tp>>
516 operator()(const experimental::propagate_const<_Tp>& __x,
517 const experimental::propagate_const<_Tp>& __y) const
519 return not_equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y));
522 typedef experimental::propagate_const<_Tp> first_argument_type;
523 typedef experimental::propagate_const<_Tp> second_argument_type;
524 typedef bool result_type;
527 template <typename _Tp>
528 struct less<experimental::propagate_const<_Tp>>
531 operator()(const experimental::propagate_const<_Tp>& __x,
532 const experimental::propagate_const<_Tp>& __y) const
534 return less<_Tp>{}(get_underlying(__x), get_underlying(__y));
537 typedef experimental::propagate_const<_Tp> first_argument_type;
538 typedef experimental::propagate_const<_Tp> second_argument_type;
539 typedef bool result_type;
542 template <typename _Tp>
543 struct greater<experimental::propagate_const<_Tp>>
546 operator()(const experimental::propagate_const<_Tp>& __x,
547 const experimental::propagate_const<_Tp>& __y) const
549 return greater<_Tp>{}(get_underlying(__x), get_underlying(__y));
552 typedef experimental::propagate_const<_Tp> first_argument_type;
553 typedef experimental::propagate_const<_Tp> second_argument_type;
554 typedef bool result_type;
557 template <typename _Tp>
558 struct less_equal<experimental::propagate_const<_Tp>>
561 operator()(const experimental::propagate_const<_Tp>& __x,
562 const experimental::propagate_const<_Tp>& __y) const
564 return less_equal<_Tp>{}(get_underlying(__x), get_underlying(__y));
567 typedef experimental::propagate_const<_Tp> first_argument_type;
568 typedef experimental::propagate_const<_Tp> second_argument_type;
569 typedef bool result_type;
572 template <typename _Tp>
573 struct greater_equal<experimental::propagate_const<_Tp>>
576 operator()(const experimental::propagate_const<_Tp>& __x,
577 const experimental::propagate_const<_Tp>& __y) const
579 return greater_equal<_Tp>{}(get_underlying(__x), get_underlying(__y));
582 typedef experimental::propagate_const<_Tp> first_argument_type;
583 typedef experimental::propagate_const<_Tp> second_argument_type;
584 typedef bool result_type;
587_GLIBCXX_END_NAMESPACE_VERSION
592#endif // _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST