libstdc++
propagate_const
Go to the documentation of this file.
1// <experimental/propagate_const> -*- C++ -*-
2
3// Copyright (C) 2015-2025 Free Software Foundation, Inc.
4//
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)
9// any later version.
10
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.
15
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.
19
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/>.
24
25/** @file experimental/propagate_const
26 * This is a TS C++ Library header.
27 * @ingroup libfund-ts
28 */
29
30#ifndef _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST
31#define _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST 1
32
33#ifdef _GLIBCXX_SYSHDR
34#pragma GCC system_header
35#endif
36
37#include <bits/requires_hosted.h> // experimental is currently omitted
38
39#if __cplusplus >= 201402L
40
41#include <type_traits>
43#include <bits/move.h>
44#include <bits/stl_function.h>
46
47namespace std _GLIBCXX_VISIBILITY(default)
48{
49_GLIBCXX_BEGIN_NAMESPACE_VERSION
50
51namespace experimental
52{
53inline namespace fundamentals_v2
54{
55 template<typename _Tp>
56 using __propagate_const_elem_type
58
59 template<typename _Tp,
60 typename _Elem = __propagate_const_elem_type<_Tp>,
61 bool = is_convertible<const _Tp, const _Elem*>::value>
62 struct __propagate_const_conversion_c
63 { };
64
65 template<typename _Tp, typename _Elem>
66 struct __propagate_const_conversion_c<_Tp, _Elem, true>
67 {
68 constexpr operator const _Elem*() const;
69 };
70
71 template<typename _Tp,
72 typename _Elem = __propagate_const_elem_type<_Tp>,
73 bool = is_convertible<_Tp, _Elem*>::value>
74 struct __propagate_const_conversion_nc
75 { };
76
77 template<typename _Tp, typename _Elem>
78 struct __propagate_const_conversion_nc<_Tp, _Elem, true>
79 {
80 constexpr operator _Elem*();
81 };
82
83 // Base class of propagate_const<T> when T is a class type.
84 template <typename _Tp>
85 struct __propagate_const_conversions
86 : __propagate_const_conversion_c<_Tp>, __propagate_const_conversion_nc<_Tp>
87 { };
88
89 // Base class of propagate_const<T> when T is a pointer type.
90 template<typename _Tp>
91 struct __propagate_const_conversions<_Tp*>
92 {
93 constexpr operator const _Tp*() const noexcept;
94 constexpr operator _Tp*() noexcept;
95 };
96
97 /**
98 * @defgroup propagate_const Const-propagating wrapper
99 * @ingroup libfund-ts
100 *
101 * A const-propagating wrapper that propagates const to pointer-like members,
102 * as described in n4388 "A Proposal to Add a Const-Propagating Wrapper
103 * to the Standard Library".
104 *
105 * @{
106 */
107
108 /// Const-propagating wrapper.
109 template <typename _Tp>
110 class propagate_const : public __propagate_const_conversions<_Tp>
111 {
112 public:
113 using element_type = __propagate_const_elem_type<_Tp>;
114
115 private:
116 template <typename _Up>
117 struct __is_propagate_const : false_type
118 { };
119
120 template <typename _Up>
121 struct __is_propagate_const<propagate_const<_Up>> : true_type
122 { };
123
124 template <typename _Up>
125 friend constexpr const _Up&
126 get_underlying(const propagate_const<_Up>& __pt) noexcept;
127 template <typename _Up>
128 friend constexpr _Up&
129 get_underlying(propagate_const<_Up>& __pt) noexcept;
130
131 template <typename _Up>
132 static constexpr element_type*
133 __to_raw_pointer(_Up* __u)
134 { return __u; }
135
136 template <typename _Up>
137 static constexpr element_type*
138 __to_raw_pointer(_Up& __u)
139 { return __u.get(); }
140
141 template <typename _Up>
142 static constexpr const element_type*
143 __to_raw_pointer(const _Up* __u)
144 { return __u; }
145
146 template <typename _Up>
147 static constexpr const element_type*
148 __to_raw_pointer(const _Up& __u)
149 { return __u.get(); }
150
151 public:
152 static_assert(__and_<is_object<typename remove_pointer<_Tp>::type>,
153 __not_<is_array<_Tp>>,
154 __or_<is_class<_Tp>, is_pointer<_Tp>>>::value,
155 "propagate_const requires a class or a pointer to an"
156 " object type");
157
158 // [propagate_const.ctor], constructors
159 constexpr propagate_const() = default;
160 propagate_const(const propagate_const& __p) = delete;
161 constexpr propagate_const(propagate_const&& __p) = default;
162
163 template <typename _Up, typename
165 is_convertible<_Up&&, _Tp>>::value, bool
166 >::type=true>
167 constexpr propagate_const(propagate_const<_Up>&& __pu)
168 : _M_t(std::move(get_underlying(__pu)))
169 {}
170
171 template <typename _Up, typename
173 __not_<is_convertible<_Up&&, _Tp>>>::value,
174 bool>::type=false>
175 constexpr explicit propagate_const(propagate_const<_Up>&& __pu)
176 : _M_t(std::move(get_underlying(__pu)))
177 {}
178
179 template <typename _Up, typename
181 is_convertible<_Up&&, _Tp>,
182 __not_<__is_propagate_const<
183 typename decay<_Up>::type>>
184 >::value, bool>::type=true>
185 constexpr propagate_const(_Up&& __u)
186 : _M_t(std::forward<_Up>(__u))
187 {}
188
189 template <typename _Up, typename
191 __not_<is_convertible<_Up&&, _Tp>>,
192 __not_<__is_propagate_const<
193 typename decay<_Up>::type>>
194 >::value, bool>::type=false>
195 constexpr explicit propagate_const(_Up&& __u)
196 : _M_t(std::forward<_Up>(__u))
197 {}
198
199 // [propagate_const.assignment], assignment
200 propagate_const& operator=(const propagate_const& __p) = delete;
201 constexpr propagate_const& operator=(propagate_const&& __p) = default;
202
203 template <typename _Up, typename =
205 constexpr propagate_const& operator=(propagate_const<_Up>&& __pu)
206 {
207 _M_t = std::move(get_underlying(__pu));
208 return *this;
209 }
210
211 template <typename _Up, typename =
213 __not_<__is_propagate_const<
214 typename decay<_Up>::type>>
215 >::value>::type>
216 constexpr propagate_const& operator=(_Up&& __u)
217 {
218 _M_t = std::forward<_Up>(__u);
219 return *this;
220 }
221
222 // [propagate_const.const_observers], const observers
223 explicit constexpr operator bool() const
224 {
225 return bool(_M_t);
226 }
227
228 constexpr const element_type* operator->() const
229 {
230 return get();
231 }
232
233 constexpr const element_type& operator*() const
234 {
235 return *get();
236 }
237
238 constexpr const element_type* get() const
239 {
240 return __to_raw_pointer(_M_t);
241 }
242
243 // [propagate_const.non_const_observers], non-const observers
244 constexpr element_type* operator->()
245 {
246 return get();
247 }
248
249 constexpr element_type& operator*()
250 {
251 return *get();
252 }
253
254 constexpr element_type* get()
255 {
256 return __to_raw_pointer(_M_t);
257 }
258
259 // [propagate_const.modifiers], modifiers
260 constexpr void
261 swap(propagate_const& __pt) noexcept(__is_nothrow_swappable<_Tp>::value)
262 {
263 using std::swap;
264 swap(_M_t, get_underlying(__pt));
265 }
266
267 private:
268 _Tp _M_t;
269 };
270
271 // [propagate_const.relational], relational operators
272 template <typename _Tp>
273 constexpr bool
274 operator==(const propagate_const<_Tp>& __pt, nullptr_t)
275 {
276 return get_underlying(__pt) == nullptr;
277 }
278
279 template <typename _Tp>
280 constexpr bool
281 operator==(nullptr_t, const propagate_const<_Tp>& __pu)
282 {
283 return nullptr == get_underlying(__pu);
284 }
285
286 template <typename _Tp>
287 constexpr bool
288 operator!=(const propagate_const<_Tp>& __pt, nullptr_t)
289 {
290 return get_underlying(__pt) != nullptr;
291 }
292
293 template <typename _Tp>
294 constexpr bool operator!=(nullptr_t, const propagate_const<_Tp>& __pu)
295 {
296 return nullptr != get_underlying(__pu);
297 }
298
299 template <typename _Tp, typename _Up>
300 constexpr bool
301 operator==(const propagate_const<_Tp>& __pt,
302 const propagate_const<_Up>& __pu)
303 {
304 return get_underlying(__pt) == get_underlying(__pu);
305 }
306
307 template <typename _Tp, typename _Up>
308 constexpr bool
309 operator!=(const propagate_const<_Tp>& __pt,
310 const propagate_const<_Up>& __pu)
311 {
312 return get_underlying(__pt) != get_underlying(__pu);
313 }
314
315 template <typename _Tp, typename _Up>
316 constexpr bool
317 operator<(const propagate_const<_Tp>& __pt,
318 const propagate_const<_Up>& __pu)
319 {
320 return get_underlying(__pt) < get_underlying(__pu);
321 }
322
323 template <typename _Tp, typename _Up>
324 constexpr bool
325 operator>(const propagate_const<_Tp>& __pt,
326 const propagate_const<_Up>& __pu)
327 {
328 return get_underlying(__pt) > get_underlying(__pu);
329 }
330
331 template <typename _Tp, typename _Up>
332 constexpr bool
333 operator<=(const propagate_const<_Tp>& __pt,
334 const propagate_const<_Up>& __pu)
335 {
336 return get_underlying(__pt) <= get_underlying(__pu);
337 }
338
339 template <typename _Tp, typename _Up>
340 constexpr bool
341 operator>=(const propagate_const<_Tp>& __pt,
342 const propagate_const<_Up>& __pu)
343 {
344 return get_underlying(__pt) >= get_underlying(__pu);
345 }
346
347 template <typename _Tp, typename _Up>
348 constexpr bool
349 operator==(const propagate_const<_Tp>& __pt, const _Up& __u)
350 {
351 return get_underlying(__pt) == __u;
352 }
353
354 template <typename _Tp, typename _Up>
355 constexpr bool
356 operator!=(const propagate_const<_Tp>& __pt, const _Up& __u)
357 {
358 return get_underlying(__pt) != __u;
359 }
360
361 template <typename _Tp, typename _Up>
362 constexpr bool
363 operator<(const propagate_const<_Tp>& __pt, const _Up& __u)
364 {
365 return get_underlying(__pt) < __u;
366 }
367
368 template <typename _Tp, typename _Up>
369 constexpr bool
370 operator>(const propagate_const<_Tp>& __pt, const _Up& __u)
371 {
372 return get_underlying(__pt) > __u;
373 }
374
375 template <typename _Tp, typename _Up>
376 constexpr bool
377 operator<=(const propagate_const<_Tp>& __pt, const _Up& __u)
378 {
379 return get_underlying(__pt) <= __u;
380 }
381
382 template <typename _Tp, typename _Up>
383 constexpr bool
384 operator>=(const propagate_const<_Tp>& __pt, const _Up& __u)
385 {
386 return get_underlying(__pt) >= __u;
387 }
388
389 template <typename _Tp, typename _Up>
390 constexpr bool
391 operator==(const _Tp& __t, const propagate_const<_Up>& __pu)
392 {
393 return __t == get_underlying(__pu);
394 }
395
396 template <typename _Tp, typename _Up>
397 constexpr bool
398 operator!=(const _Tp& __t, const propagate_const<_Up>& __pu)
399 {
400 return __t != get_underlying(__pu);
401 }
402
403 template <typename _Tp, typename _Up>
404 constexpr bool
405 operator<(const _Tp& __t, const propagate_const<_Up>& __pu)
406 {
407 return __t < get_underlying(__pu);
408 }
409
410 template <typename _Tp, typename _Up>
411 constexpr bool
412 operator>(const _Tp& __t, const propagate_const<_Up>& __pu)
413 {
414 return __t > get_underlying(__pu);
415 }
416
417 template <typename _Tp, typename _Up>
418 constexpr bool
419 operator<=(const _Tp& __t, const propagate_const<_Up>& __pu)
420 {
421 return __t <= get_underlying(__pu);
422 }
423
424 template <typename _Tp, typename _Up>
425 constexpr bool
426 operator>=(const _Tp& __t, const propagate_const<_Up>& __pu)
427 {
428 return __t >= get_underlying(__pu);
429 }
430
431 // [propagate_const.algorithms], specialized algorithms
432 // _GLIBCXX_RESOLVE_LIB_DEFECTS
433 // 3413. propagate_const's swap [...] needs to be constrained and use a trait
434 template <typename _Tp>
435 constexpr enable_if_t<__is_swappable<_Tp>::value, void>
437 noexcept(__is_nothrow_swappable<_Tp>::value)
438 {
439 __pt.swap(__pt2);
440 }
441
442 // [propagate_const.underlying], underlying pointer access
443 template <typename _Tp>
444 constexpr const _Tp&
445 get_underlying(const propagate_const<_Tp>& __pt) noexcept
446 {
447 return __pt._M_t;
448 }
449
450 template <typename _Tp>
451 constexpr _Tp&
452 get_underlying(propagate_const<_Tp>& __pt) noexcept
453 {
454 return __pt._M_t;
455 }
456
457 template<typename _Tp>
458 constexpr
459 __propagate_const_conversions<_Tp*>::operator const _Tp*() const noexcept
460 { return static_cast<const propagate_const<_Tp*>*>(this)->get(); }
461
462 template<typename _Tp>
463 constexpr
464 __propagate_const_conversions<_Tp*>::operator _Tp*() noexcept
465 { return static_cast<propagate_const<_Tp*>*>(this)->get(); }
466
467 template<typename _Tp, typename _Elem>
468 constexpr
469 __propagate_const_conversion_c<_Tp, _Elem, true>::
470 operator const _Elem*() const
471 { return static_cast<const propagate_const<_Tp>*>(this)->get(); }
472
473 template<typename _Tp, typename _Elem>
474 constexpr
475 __propagate_const_conversion_nc<_Tp, _Elem, true>::
476 operator _Elem*()
477 { return static_cast<propagate_const<_Tp>*>(this)->get(); }
478
479 /// @} group propagate_const
480} // namespace fundamentals_v2
481} // namespace experimental
482
483// [propagate_const.hash], hash support
484 template <typename _Tp>
485 struct hash<experimental::propagate_const<_Tp>>
486 {
487 using result_type = size_t;
488 using argument_type = experimental::propagate_const<_Tp>;
489
490 size_t
491 operator()(const experimental::propagate_const<_Tp>& __t) const
492 noexcept(noexcept(hash<_Tp>{}(get_underlying(__t))))
493 {
494 return hash<_Tp>{}(get_underlying(__t));
495 }
496 };
497
498 // [propagate_const.comparison_function_objects], comparison function objects
499 template <typename _Tp>
500 struct equal_to<experimental::propagate_const<_Tp>>
501 {
502 constexpr bool
503 operator()(const experimental::propagate_const<_Tp>& __x,
504 const experimental::propagate_const<_Tp>& __y) const
505 {
506 return equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y));
507 }
508
509 typedef experimental::propagate_const<_Tp> first_argument_type;
510 typedef experimental::propagate_const<_Tp> second_argument_type;
511 typedef bool result_type;
512 };
513
514 template <typename _Tp>
515 struct not_equal_to<experimental::propagate_const<_Tp>>
516 {
517 constexpr bool
518 operator()(const experimental::propagate_const<_Tp>& __x,
519 const experimental::propagate_const<_Tp>& __y) const
520 {
521 return not_equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y));
522 }
523
524 typedef experimental::propagate_const<_Tp> first_argument_type;
525 typedef experimental::propagate_const<_Tp> second_argument_type;
526 typedef bool result_type;
527 };
528
529 template <typename _Tp>
530 struct less<experimental::propagate_const<_Tp>>
531 {
532 constexpr bool
533 operator()(const experimental::propagate_const<_Tp>& __x,
534 const experimental::propagate_const<_Tp>& __y) const
535 {
536 return less<_Tp>{}(get_underlying(__x), get_underlying(__y));
537 }
538
539 typedef experimental::propagate_const<_Tp> first_argument_type;
540 typedef experimental::propagate_const<_Tp> second_argument_type;
541 typedef bool result_type;
542 };
543
544 template <typename _Tp>
545 struct greater<experimental::propagate_const<_Tp>>
546 {
547 constexpr bool
548 operator()(const experimental::propagate_const<_Tp>& __x,
549 const experimental::propagate_const<_Tp>& __y) const
550 {
551 return greater<_Tp>{}(get_underlying(__x), get_underlying(__y));
552 }
553
554 typedef experimental::propagate_const<_Tp> first_argument_type;
555 typedef experimental::propagate_const<_Tp> second_argument_type;
556 typedef bool result_type;
557 };
558
559 template <typename _Tp>
560 struct less_equal<experimental::propagate_const<_Tp>>
561 {
562 constexpr bool
563 operator()(const experimental::propagate_const<_Tp>& __x,
564 const experimental::propagate_const<_Tp>& __y) const
565 {
566 return less_equal<_Tp>{}(get_underlying(__x), get_underlying(__y));
567 }
568
569 typedef experimental::propagate_const<_Tp> first_argument_type;
570 typedef experimental::propagate_const<_Tp> second_argument_type;
571 typedef bool result_type;
572 };
573
574 template <typename _Tp>
575 struct greater_equal<experimental::propagate_const<_Tp>>
576 {
577 constexpr bool
578 operator()(const experimental::propagate_const<_Tp>& __x,
579 const experimental::propagate_const<_Tp>& __y) const
580 {
581 return greater_equal<_Tp>{}(get_underlying(__x), get_underlying(__y));
582 }
583
584 typedef experimental::propagate_const<_Tp> first_argument_type;
585 typedef experimental::propagate_const<_Tp> second_argument_type;
586 typedef bool result_type;
587 };
588
589_GLIBCXX_END_NAMESPACE_VERSION
590} // namespace std
591
592#endif // C++14
593
594#endif // _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST
__bool_constant< true > true_type
The type used as a compile-time boolean with true value.
Definition type_traits:116
typename remove_reference< _Tp >::type remove_reference_t
Alias template for remove_reference.
Definition type_traits:1798
__bool_constant< false > false_type
The type used as a compile-time boolean with false value.
Definition type_traits:119
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:138
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:72
ISO C++ entities toplevel namespace is std.
Namespace for features defined in ISO Technical Specifications.
Primary class template hash.
Define a member typedef type only if a boolean constant is true.
Definition type_traits:134
is_pointer
Definition type_traits:554
One of the comparison functors.
One of the comparison functors.
One of the comparison functors.
One of the comparison functors.
One of the comparison functors.
One of the comparison functors.