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>
40 #include <bits/functional_hash.h>
41 #include <bits/move.h>
42 #include <bits/stl_function.h>
43 #include <experimental/bits/lfts_config.h>
44 
45 namespace std _GLIBCXX_VISIBILITY(default)
46 {
47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
48 
49 namespace experimental
50 {
51 inline 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
162  enable_if<__and_<is_constructible<_Tp, _Up&&>,
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
170  enable_if<__and_<is_constructible<_Tp, _Up&&>,
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
178  enable_if<__and_<is_constructible<_Tp, _Up&&>,
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
188  enable_if<__and_<is_constructible<_Tp, _Up&&>,
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 =
202  typename enable_if<is_convertible<_Up&&, _Tp>::value>::type>
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 =
210  typename enable_if<__and_<is_convertible<_Up&&, _Tp>,
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