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