libstdc++
propagate_const
Go to the documentation of this file.
1 // <experimental/propagate_const> -*- C++ -*-
2 
3 // Copyright (C) 2015-2022 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 
43 namespace std _GLIBCXX_VISIBILITY(default)
44 {
45 _GLIBCXX_BEGIN_NAMESPACE_VERSION
46 
47 namespace experimental
48 {
49 inline 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