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>
42#include <bits/functional_hash.h>
43#include <bits/move.h>
44#include <bits/stl_function.h>
45#include <experimental/bits/lfts_config.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
57 = remove_reference_t<decltype(*std::declval<_Tp&>())>;
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
164 enable_if<__and_<is_constructible<_Tp, _Up&&>,
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
172 enable_if<__and_<is_constructible<_Tp, _Up&&>,
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
180 enable_if<__and_<is_constructible<_Tp, _Up&&>,
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
190 enable_if<__and_<is_constructible<_Tp, _Up&&>,
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 =
204 typename enable_if<is_convertible<_Up&&, _Tp>::value>::type>
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 =
212 typename enable_if<__and_<is_convertible<_Up&&, _Tp>,
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>
436 swap(propagate_const<_Tp>& __pt, propagate_const<_Tp>& __pt2)
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