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 
47 namespace std _GLIBCXX_VISIBILITY(default)
48 {
49 _GLIBCXX_BEGIN_NAMESPACE_VERSION
50 
51 namespace experimental
52 {
53 inline 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