libstdc++
propagate_const
Go to the documentation of this file.
1// <experimental/propagate_const> -*- C++ -*-
2
3// Copyright (C) 2015-2021 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#if __cplusplus >= 201402L
36
37#include <type_traits>
38#include <bits/functional_hash.h>
39#include <bits/move.h>
40#include <bits/stl_function.h>
41#include <experimental/bits/lfts_config.h>
42
43namespace std _GLIBCXX_VISIBILITY(default)
44{
45_GLIBCXX_BEGIN_NAMESPACE_VERSION
46
47namespace experimental
48{
49inline namespace fundamentals_v2
50{
51 /**
52 * @defgroup propagate_const Const-propagating wrapper
53 * @ingroup libfund-ts
54 *
55 * A const-propagating wrapper that propagates const to pointer-like members,
56 * as described in n4388 "A Proposal to Add a Const-Propagating Wrapper
57 * to the Standard Library".
58 *
59 * @{
60 */
61
62 /// Const-propagating wrapper.
63 template <typename _Tp>
64 class propagate_const
65 {
66 public:
67 typedef remove_reference_t<decltype(*std::declval<_Tp&>())> element_type;
68
69 private:
70 template <typename _Up>
71 struct __is_propagate_const : false_type
72 { };
73
74 template <typename _Up>
75 struct __is_propagate_const<propagate_const<_Up>> : true_type
76 { };
77
78 template <typename _Up>
79 friend constexpr const _Up&
80 get_underlying(const propagate_const<_Up>& __pt) noexcept;
81 template <typename _Up>
82 friend constexpr _Up&
83 get_underlying(propagate_const<_Up>& __pt) noexcept;
84
85 template <typename _Up>
86 static constexpr element_type*
87 __to_raw_pointer(_Up* __u)
88 { return __u; }
89
90 template <typename _Up>
91 static constexpr element_type*
92 __to_raw_pointer(_Up& __u)
93 { return __u.get(); }
94
95 template <typename _Up>
96 static constexpr const element_type*
97 __to_raw_pointer(const _Up* __u)
98 { return __u; }
99
100 template <typename _Up>
101 static constexpr const element_type*
102 __to_raw_pointer(const _Up& __u)
103 { return __u.get(); }
104
105 public:
106 static_assert(__and_<is_object<typename remove_pointer<_Tp>::type>,
107 __not_<is_array<_Tp>>,
108 __or_<is_class<_Tp>, is_pointer<_Tp>>>::value,
109 "propagate_const requires a class or a pointer to an"
110 " object type");
111
112 // [propagate_const.ctor], constructors
113 constexpr propagate_const() = default;
114 propagate_const(const propagate_const& __p) = delete;
115 constexpr propagate_const(propagate_const&& __p) = default;
116
117 template <typename _Up, typename
118 enable_if<__and_<is_constructible<_Tp, _Up&&>,
119 is_convertible<_Up&&, _Tp>>::value, bool
120 >::type=true>
121 constexpr propagate_const(propagate_const<_Up>&& __pu)
122 : _M_t(std::move(get_underlying(__pu)))
123 {}
124
125 template <typename _Up, typename
126 enable_if<__and_<is_constructible<_Tp, _Up&&>,
127 __not_<is_convertible<_Up&&, _Tp>>>::value,
128 bool>::type=false>
129 constexpr explicit propagate_const(propagate_const<_Up>&& __pu)
130 : _M_t(std::move(get_underlying(__pu)))
131 {}
132
133 template <typename _Up, typename
134 enable_if<__and_<is_constructible<_Tp, _Up&&>,
135 is_convertible<_Up&&, _Tp>,
136 __not_<__is_propagate_const<
137 typename decay<_Up>::type>>
138 >::value, bool>::type=true>
139 constexpr propagate_const(_Up&& __u)
140 : _M_t(std::forward<_Up>(__u))
141 {}
142
143 template <typename _Up, typename
144 enable_if<__and_<is_constructible<_Tp, _Up&&>,
145 __not_<is_convertible<_Up&&, _Tp>>,
146 __not_<__is_propagate_const<
147 typename decay<_Up>::type>>
148 >::value, bool>::type=false>
149 constexpr explicit propagate_const(_Up&& __u)
150 : _M_t(std::forward<_Up>(__u))
151 {}
152
153 // [propagate_const.assignment], assignment
154 propagate_const& operator=(const propagate_const& __p) = delete;
155 constexpr propagate_const& operator=(propagate_const&& __p) = default;
156
157 template <typename _Up, typename =
158 typename enable_if<is_convertible<_Up&&, _Tp>::value>::type>
159 constexpr propagate_const& operator=(propagate_const<_Up>&& __pu)
160 {
161 _M_t = std::move(get_underlying(__pu));
162 return *this;
163 }
164
165 template <typename _Up, typename =
166 typename enable_if<__and_<is_convertible<_Up&&, _Tp>,
167 __not_<__is_propagate_const<
168 typename decay<_Up>::type>>
169 >::value>::type>
170 constexpr propagate_const& operator=(_Up&& __u)
171 {
172 _M_t = std::forward<_Up>(__u);
173 return *this;
174 }
175
176 // [propagate_const.const_observers], const observers
177 explicit constexpr operator bool() const
178 {
179 return bool(_M_t);
180 }
181
182 constexpr const element_type* operator->() const
183 {
184 return get();
185 }
186
187 template <typename _Up = _Tp,
188 typename enable_if<__or_<is_pointer<_Up>,
189 is_convertible<_Up,
190 const element_type*>
191 >::value, bool>::type = true>
192 constexpr operator const element_type*() const
193 {
194 return get();
195 }
196
197 constexpr const element_type& operator*() const
198 {
199 return *get();
200 }
201
202 constexpr const element_type* get() const
203 {
204 return __to_raw_pointer(_M_t);
205 }
206
207 // [propagate_const.non_const_observers], non-const observers
208 constexpr element_type* operator->()
209 {
210 return get();
211 }
212
213 template <typename _Up = _Tp,
214 typename enable_if<__or_<is_pointer<_Up>,
215 is_convertible<_Up,
216 const element_type*>
217 >::value, bool>::type = true>
218 constexpr operator element_type*()
219 {
220 return get();
221 }
222
223 constexpr element_type& operator*()
224 {
225 return *get();
226 }
227
228 constexpr element_type* get()
229 {
230 return __to_raw_pointer(_M_t);
231 }
232
233 // [propagate_const.modifiers], modifiers
234 constexpr void
235 swap(propagate_const& __pt) noexcept(__is_nothrow_swappable<_Tp>::value)
236 {
237 using std::swap;
238 swap(_M_t, get_underlying(__pt));
239 }
240
241 private:
242 _Tp _M_t;
243 };
244
245 // [propagate_const.relational], relational operators
246 template <typename _Tp>
247 constexpr bool
248 operator==(const propagate_const<_Tp>& __pt, nullptr_t)
249 {
250 return get_underlying(__pt) == nullptr;
251 }
252
253 template <typename _Tp>
254 constexpr bool
255 operator==(nullptr_t, const propagate_const<_Tp>& __pu)
256 {
257 return nullptr == get_underlying(__pu);
258 }
259
260 template <typename _Tp>
261 constexpr bool
262 operator!=(const propagate_const<_Tp>& __pt, nullptr_t)
263 {
264 return get_underlying(__pt) != nullptr;
265 }
266
267 template <typename _Tp>
268 constexpr bool operator!=(nullptr_t, const propagate_const<_Tp>& __pu)
269 {
270 return nullptr != get_underlying(__pu);
271 }
272
273 template <typename _Tp, typename _Up>
274 constexpr bool
275 operator==(const propagate_const<_Tp>& __pt,
276 const propagate_const<_Up>& __pu)
277 {
278 return get_underlying(__pt) == get_underlying(__pu);
279 }
280
281 template <typename _Tp, typename _Up>
282 constexpr bool
283 operator!=(const propagate_const<_Tp>& __pt,
284 const propagate_const<_Up>& __pu)
285 {
286 return get_underlying(__pt) != get_underlying(__pu);
287 }
288
289 template <typename _Tp, typename _Up>
290 constexpr bool
291 operator<(const propagate_const<_Tp>& __pt,
292 const propagate_const<_Up>& __pu)
293 {
294 return get_underlying(__pt) < 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, const _Up& __u)
324 {
325 return get_underlying(__pt) == __u;
326 }
327
328 template <typename _Tp, typename _Up>
329 constexpr bool
330 operator!=(const propagate_const<_Tp>& __pt, const _Up& __u)
331 {
332 return get_underlying(__pt) != __u;
333 }
334
335 template <typename _Tp, typename _Up>
336 constexpr bool
337 operator<(const propagate_const<_Tp>& __pt, const _Up& __u)
338 {
339 return get_underlying(__pt) < __u;
340 }
341
342 template <typename _Tp, typename _Up>
343 constexpr bool
344 operator>(const propagate_const<_Tp>& __pt, const _Up& __u)
345 {
346 return get_underlying(__pt) > __u;
347 }
348
349 template <typename _Tp, typename _Up>
350 constexpr bool
351 operator<=(const propagate_const<_Tp>& __pt, const _Up& __u)
352 {
353 return get_underlying(__pt) <= __u;
354 }
355
356 template <typename _Tp, typename _Up>
357 constexpr bool
358 operator>=(const propagate_const<_Tp>& __pt, const _Up& __u)
359 {
360 return get_underlying(__pt) >= __u;
361 }
362
363 template <typename _Tp, typename _Up>
364 constexpr bool
365 operator==(const _Tp& __t, const propagate_const<_Up>& __pu)
366 {
367 return __t == get_underlying(__pu);
368 }
369
370 template <typename _Tp, typename _Up>
371 constexpr bool
372 operator!=(const _Tp& __t, const propagate_const<_Up>& __pu)
373 {
374 return __t != get_underlying(__pu);
375 }
376
377 template <typename _Tp, typename _Up>
378 constexpr bool
379 operator<(const _Tp& __t, const propagate_const<_Up>& __pu)
380 {
381 return __t < get_underlying(__pu);
382 }
383
384 template <typename _Tp, typename _Up>
385 constexpr bool
386 operator>(const _Tp& __t, const propagate_const<_Up>& __pu)
387 {
388 return __t > get_underlying(__pu);
389 }
390
391 template <typename _Tp, typename _Up>
392 constexpr bool
393 operator<=(const _Tp& __t, const propagate_const<_Up>& __pu)
394 {
395 return __t <= get_underlying(__pu);
396 }
397
398 template <typename _Tp, typename _Up>
399 constexpr bool
400 operator>=(const _Tp& __t, const propagate_const<_Up>& __pu)
401 {
402 return __t >= get_underlying(__pu);
403 }
404
405 // [propagate_const.algorithms], specialized algorithms
406 // _GLIBCXX_RESOLVE_LIB_DEFECTS
407 // 3413. propagate_const's swap [...] needs to be constrained and use a trait
408 template <typename _Tp>
409 constexpr enable_if_t<__is_swappable<_Tp>::value, void>
410 swap(propagate_const<_Tp>& __pt, propagate_const<_Tp>& __pt2)
411 noexcept(__is_nothrow_swappable<_Tp>::value)
412 {
413 __pt.swap(__pt2);
414 }
415
416 // [propagate_const.underlying], underlying pointer access
417 template <typename _Tp>
418 constexpr const _Tp&
419 get_underlying(const propagate_const<_Tp>& __pt) noexcept
420 {
421 return __pt._M_t;
422 }
423
424 template <typename _Tp>
425 constexpr _Tp&
426 get_underlying(propagate_const<_Tp>& __pt) noexcept
427 {
428 return __pt._M_t;
429 }
430
431 /// @} group propagate_const
432} // namespace fundamentals_v2
433} // namespace experimental
434
435// [propagate_const.hash], hash support
436 template <typename _Tp>
437 struct hash<experimental::propagate_const<_Tp>>
438 {
439 using result_type = size_t;
440 using argument_type = experimental::propagate_const<_Tp>;
441
442 size_t
443 operator()(const experimental::propagate_const<_Tp>& __t) const
444 noexcept(noexcept(hash<_Tp>{}(get_underlying(__t))))
445 {
446 return hash<_Tp>{}(get_underlying(__t));
447 }
448 };
449
450 // [propagate_const.comparison_function_objects], comparison function objects
451 template <typename _Tp>
452 struct equal_to<experimental::propagate_const<_Tp>>
453 {
454 constexpr bool
455 operator()(const experimental::propagate_const<_Tp>& __x,
456 const experimental::propagate_const<_Tp>& __y) const
457 {
458 return equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y));
459 }
460
461 typedef experimental::propagate_const<_Tp> first_argument_type;
462 typedef experimental::propagate_const<_Tp> second_argument_type;
463 typedef bool result_type;
464 };
465
466 template <typename _Tp>
467 struct not_equal_to<experimental::propagate_const<_Tp>>
468 {
469 constexpr bool
470 operator()(const experimental::propagate_const<_Tp>& __x,
471 const experimental::propagate_const<_Tp>& __y) const
472 {
473 return not_equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y));
474 }
475
476 typedef experimental::propagate_const<_Tp> first_argument_type;
477 typedef experimental::propagate_const<_Tp> second_argument_type;
478 typedef bool result_type;
479 };
480
481 template <typename _Tp>
482 struct less<experimental::propagate_const<_Tp>>
483 {
484 constexpr bool
485 operator()(const experimental::propagate_const<_Tp>& __x,
486 const experimental::propagate_const<_Tp>& __y) const
487 {
488 return less<_Tp>{}(get_underlying(__x), get_underlying(__y));
489 }
490
491 typedef experimental::propagate_const<_Tp> first_argument_type;
492 typedef experimental::propagate_const<_Tp> second_argument_type;
493 typedef bool result_type;
494 };
495
496 template <typename _Tp>
497 struct greater<experimental::propagate_const<_Tp>>
498 {
499 constexpr bool
500 operator()(const experimental::propagate_const<_Tp>& __x,
501 const experimental::propagate_const<_Tp>& __y) const
502 {
503 return greater<_Tp>{}(get_underlying(__x), get_underlying(__y));
504 }
505
506 typedef experimental::propagate_const<_Tp> first_argument_type;
507 typedef experimental::propagate_const<_Tp> second_argument_type;
508 typedef bool result_type;
509 };
510
511 template <typename _Tp>
512 struct less_equal<experimental::propagate_const<_Tp>>
513 {
514 constexpr bool
515 operator()(const experimental::propagate_const<_Tp>& __x,
516 const experimental::propagate_const<_Tp>& __y) const
517 {
518 return less_equal<_Tp>{}(get_underlying(__x), get_underlying(__y));
519 }
520
521 typedef experimental::propagate_const<_Tp> first_argument_type;
522 typedef experimental::propagate_const<_Tp> second_argument_type;
523 typedef bool result_type;
524 };
525
526 template <typename _Tp>
527 struct greater_equal<experimental::propagate_const<_Tp>>
528 {
529 constexpr bool
530 operator()(const experimental::propagate_const<_Tp>& __x,
531 const experimental::propagate_const<_Tp>& __y) const
532 {
533 return greater_equal<_Tp>{}(get_underlying(__x), get_underlying(__y));
534 }
535
536 typedef experimental::propagate_const<_Tp> first_argument_type;
537 typedef experimental::propagate_const<_Tp> second_argument_type;
538 typedef bool result_type;
539 };
540
541_GLIBCXX_END_NAMESPACE_VERSION
542} // namespace std
543
544#endif // C++14
545
546#endif // _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST