libstdc++
propagate_const
Go to the documentation of this file.
1// <experimental/propagate_const> -*- C++ -*-
2
3// Copyright (C) 2015-2023 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
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
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))
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>
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
typename remove_reference< _Tp >::type remove_reference_t
Alias template for remove_reference.
Definition type_traits:1638
integral_constant< bool, true > true_type
The type used as a compile-time boolean with true value.
Definition type_traits:82
integral_constant< bool, false > false_type
The type used as a compile-time boolean with false value.
Definition type_traits:85
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:97
void swap(any &__x, any &__y) noexcept
Exchange the states of two any objects.
Definition any:429
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:70
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:107
is_pointer
Definition type_traits:529
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.