libstdc++
propagate_const
Go to the documentation of this file.
1 // <experimental/propagate_const> -*- C++ -*-
2 
3 // Copyright (C) 2015-2020 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  template <typename _Up, typename
117  enable_if<__and_<is_constructible<_Tp, _Up&&>,
118  is_convertible<_Up&&, _Tp>>::value, bool
119  >::type=true>
120  constexpr propagate_const(propagate_const<_Up>&& __pu)
121  : _M_t(std::move(get_underlying(__pu)))
122  {}
123  template <typename _Up, typename
124  enable_if<__and_<is_constructible<_Tp, _Up&&>,
125  __not_<is_convertible<_Up&&, _Tp>>>::value,
126  bool>::type=false>
127  constexpr explicit propagate_const(propagate_const<_Up>&& __pu)
128  : _M_t(std::move(get_underlying(__pu)))
129  {}
130  template <typename _Up, typename
131  enable_if<__and_<is_constructible<_Tp, _Up&&>,
132  is_convertible<_Up&&, _Tp>,
133  __not_<__is_propagate_const<
134  typename decay<_Up>::type>>
135  >::value, bool>::type=true>
136  constexpr propagate_const(_Up&& __u)
137  : _M_t(std::forward<_Up>(__u))
138  {}
139  template <typename _Up, typename
140  enable_if<__and_<is_constructible<_Tp, _Up&&>,
141  __not_<is_convertible<_Up&&, _Tp>>,
142  __not_<__is_propagate_const<
143  typename decay<_Up>::type>>
144  >::value, bool>::type=false>
145  constexpr explicit propagate_const(_Up&& __u)
146  : _M_t(std::forward<_Up>(__u))
147  {}
148 
149  // [propagate_const.assignment], assignment
150  propagate_const& operator=(const propagate_const& __p) = delete;
151  constexpr propagate_const& operator=(propagate_const&& __p) = default;
152 
153  template <typename _Up, typename =
154  typename enable_if<is_convertible<_Up&&, _Tp>::value>::type>
155  constexpr propagate_const& operator=(propagate_const<_Up>&& __pu)
156  {
157  _M_t = std::move(get_underlying(__pu));
158  return *this;
159  }
160 
161  template <typename _Up, typename =
162  typename enable_if<__and_<is_convertible<_Up&&, _Tp>,
163  __not_<__is_propagate_const<
164  typename decay<_Up>::type>>
165  >::value>::type>
166  constexpr propagate_const& operator=(_Up&& __u)
167  {
168  _M_t = std::forward<_Up>(__u);
169  return *this;
170  }
171 
172  // [propagate_const.const_observers], const observers
173  explicit constexpr operator bool() const
174  {
175  return bool(_M_t);
176  }
177 
178  constexpr const element_type* operator->() const
179  {
180  return get();
181  }
182 
183  template <typename _Up = _Tp,
184  typename enable_if<__or_<is_pointer<_Up>,
185  is_convertible<_Up,
186  const element_type*>
187  >::value, bool>::type = true>
188  constexpr operator const element_type*() const
189  {
190  return get();
191  }
192 
193  constexpr const element_type& operator*() const
194  {
195  return *get();
196  }
197 
198  constexpr const element_type* get() const
199  {
200  return __to_raw_pointer(_M_t);
201  }
202 
203  // [propagate_const.non_const_observers], non-const observers
204  constexpr element_type* operator->()
205  {
206  return get();
207  }
208 
209  template <typename _Up = _Tp,
210  typename enable_if<__or_<is_pointer<_Up>,
211  is_convertible<_Up,
212  const element_type*>
213  >::value, bool>::type = true>
214  constexpr operator element_type*()
215  {
216  return get();
217  }
218 
219  constexpr element_type& operator*()
220  {
221  return *get();
222  }
223 
224  constexpr element_type* get()
225  {
226  return __to_raw_pointer(_M_t);
227  }
228 
229  // [propagate_const.modifiers], modifiers
230  constexpr void
231  swap(propagate_const& __pt) noexcept(__is_nothrow_swappable<_Tp>::value)
232  {
233  using std::swap;
234  swap(_M_t, get_underlying(__pt));
235  }
236 
237  private:
238  _Tp _M_t;
239  };
240 
241  // [propagate_const.relational], relational operators
242  template <typename _Tp>
243  constexpr bool
244  operator==(const propagate_const<_Tp>& __pt, nullptr_t)
245  {
246  return get_underlying(__pt) == nullptr;
247  }
248 
249  template <typename _Tp>
250  constexpr bool
251  operator==(nullptr_t, const propagate_const<_Tp>& __pu)
252  {
253  return nullptr == get_underlying(__pu);
254  }
255 
256  template <typename _Tp>
257  constexpr bool
258  operator!=(const propagate_const<_Tp>& __pt, nullptr_t)
259  {
260  return get_underlying(__pt) != nullptr;
261  }
262 
263  template <typename _Tp>
264  constexpr bool operator!=(nullptr_t, const propagate_const<_Tp>& __pu)
265  {
266  return nullptr != get_underlying(__pu);
267  }
268 
269  template <typename _Tp, typename _Up>
270  constexpr bool
271  operator==(const propagate_const<_Tp>& __pt,
272  const propagate_const<_Up>& __pu)
273  {
274  return get_underlying(__pt) == get_underlying(__pu);
275  }
276 
277  template <typename _Tp, typename _Up>
278  constexpr bool
279  operator!=(const propagate_const<_Tp>& __pt,
280  const propagate_const<_Up>& __pu)
281  {
282  return get_underlying(__pt) != get_underlying(__pu);
283  }
284 
285  template <typename _Tp, typename _Up>
286  constexpr bool
287  operator<(const propagate_const<_Tp>& __pt,
288  const propagate_const<_Up>& __pu)
289  {
290  return get_underlying(__pt) < get_underlying(__pu);
291  }
292 
293  template <typename _Tp, typename _Up>
294  constexpr bool
295  operator>(const propagate_const<_Tp>& __pt,
296  const propagate_const<_Up>& __pu)
297  {
298  return get_underlying(__pt) > get_underlying(__pu);
299  }
300 
301  template <typename _Tp, typename _Up>
302  constexpr bool
303  operator<=(const propagate_const<_Tp>& __pt,
304  const propagate_const<_Up>& __pu)
305  {
306  return get_underlying(__pt) <= get_underlying(__pu);
307  }
308 
309  template <typename _Tp, typename _Up>
310  constexpr bool
311  operator>=(const propagate_const<_Tp>& __pt,
312  const propagate_const<_Up>& __pu)
313  {
314  return get_underlying(__pt) >= get_underlying(__pu);
315  }
316 
317  template <typename _Tp, typename _Up>
318  constexpr bool
319  operator==(const propagate_const<_Tp>& __pt, const _Up& __u)
320  {
321  return get_underlying(__pt) == __u;
322  }
323 
324  template <typename _Tp, typename _Up>
325  constexpr bool
326  operator!=(const propagate_const<_Tp>& __pt, const _Up& __u)
327  {
328  return get_underlying(__pt) != __u;
329  }
330 
331  template <typename _Tp, typename _Up>
332  constexpr bool
333  operator<(const propagate_const<_Tp>& __pt, const _Up& __u)
334  {
335  return get_underlying(__pt) < __u;
336  }
337 
338  template <typename _Tp, typename _Up>
339  constexpr bool
340  operator>(const propagate_const<_Tp>& __pt, const _Up& __u)
341  {
342  return get_underlying(__pt) > __u;
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 _Tp& __t, const propagate_const<_Up>& __pu)
362  {
363  return __t == get_underlying(__pu);
364  }
365 
366  template <typename _Tp, typename _Up>
367  constexpr bool
368  operator!=(const _Tp& __t, const propagate_const<_Up>& __pu)
369  {
370  return __t != get_underlying(__pu);
371  }
372 
373  template <typename _Tp, typename _Up>
374  constexpr bool
375  operator<(const _Tp& __t, const propagate_const<_Up>& __pu)
376  {
377  return __t < get_underlying(__pu);
378  }
379 
380  template <typename _Tp, typename _Up>
381  constexpr bool
382  operator>(const _Tp& __t, const propagate_const<_Up>& __pu)
383  {
384  return __t > get_underlying(__pu);
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  // [propagate_const.algorithms], specialized algorithms
402  template <typename _Tp>
403  constexpr void
404  swap(propagate_const<_Tp>& __pt, propagate_const<_Tp>& __pt2)
405  noexcept(__is_nothrow_swappable<_Tp>::value)
406  {
407  __pt.swap(__pt2);
408  }
409 
410  // [propagate_const.underlying], underlying pointer access
411  template <typename _Tp>
412  constexpr const _Tp&
413  get_underlying(const propagate_const<_Tp>& __pt) noexcept
414  {
415  return __pt._M_t;
416  }
417 
418  template <typename _Tp>
419  constexpr _Tp&
420  get_underlying(propagate_const<_Tp>& __pt) noexcept
421  {
422  return __pt._M_t;
423  }
424 
425  /// @} group propagate_const
426 } // namespace fundamentals_v2
427 } // namespace experimental
428 
429 // [propagate_const.hash], hash support
430  template <typename _Tp>
431  struct hash<experimental::propagate_const<_Tp>>
432  {
433  using result_type = size_t;
434  using argument_type = experimental::propagate_const<_Tp>;
435 
436  size_t
437  operator()(const experimental::propagate_const<_Tp>& __t) const
438  noexcept(noexcept(hash<_Tp>{}(get_underlying(__t))))
439  {
440  return hash<_Tp>{}(get_underlying(__t));
441  }
442  };
443 
444  // [propagate_const.comparison_function_objects], comparison function objects
445  template <typename _Tp>
446  struct equal_to<experimental::propagate_const<_Tp>>
447  {
448  constexpr bool
449  operator()(const experimental::propagate_const<_Tp>& __x,
450  const experimental::propagate_const<_Tp>& __y) const
451  {
452  return equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y));
453  }
454 
455  typedef experimental::propagate_const<_Tp> first_argument_type;
456  typedef experimental::propagate_const<_Tp> second_argument_type;
457  typedef bool result_type;
458  };
459 
460  template <typename _Tp>
461  struct not_equal_to<experimental::propagate_const<_Tp>>
462  {
463  constexpr bool
464  operator()(const experimental::propagate_const<_Tp>& __x,
465  const experimental::propagate_const<_Tp>& __y) const
466  {
467  return not_equal_to<_Tp>{}(get_underlying(__x), get_underlying(__y));
468  }
469 
470  typedef experimental::propagate_const<_Tp> first_argument_type;
471  typedef experimental::propagate_const<_Tp> second_argument_type;
472  typedef bool result_type;
473  };
474 
475  template <typename _Tp>
476  struct less<experimental::propagate_const<_Tp>>
477  {
478  constexpr bool
479  operator()(const experimental::propagate_const<_Tp>& __x,
480  const experimental::propagate_const<_Tp>& __y) const
481  {
482  return less<_Tp>{}(get_underlying(__x), get_underlying(__y));
483  }
484 
485  typedef experimental::propagate_const<_Tp> first_argument_type;
486  typedef experimental::propagate_const<_Tp> second_argument_type;
487  typedef bool result_type;
488  };
489 
490  template <typename _Tp>
491  struct greater<experimental::propagate_const<_Tp>>
492  {
493  constexpr bool
494  operator()(const experimental::propagate_const<_Tp>& __x,
495  const experimental::propagate_const<_Tp>& __y) const
496  {
497  return greater<_Tp>{}(get_underlying(__x), get_underlying(__y));
498  }
499 
500  typedef experimental::propagate_const<_Tp> first_argument_type;
501  typedef experimental::propagate_const<_Tp> second_argument_type;
502  typedef bool result_type;
503  };
504 
505  template <typename _Tp>
506  struct less_equal<experimental::propagate_const<_Tp>>
507  {
508  constexpr bool
509  operator()(const experimental::propagate_const<_Tp>& __x,
510  const experimental::propagate_const<_Tp>& __y) const
511  {
512  return less_equal<_Tp>{}(get_underlying(__x), get_underlying(__y));
513  }
514 
515  typedef experimental::propagate_const<_Tp> first_argument_type;
516  typedef experimental::propagate_const<_Tp> second_argument_type;
517  typedef bool result_type;
518  };
519 
520  template <typename _Tp>
521  struct greater_equal<experimental::propagate_const<_Tp>>
522  {
523  constexpr bool
524  operator()(const experimental::propagate_const<_Tp>& __x,
525  const experimental::propagate_const<_Tp>& __y) const
526  {
527  return greater_equal<_Tp>{}(get_underlying(__x), get_underlying(__y));
528  }
529 
530  typedef experimental::propagate_const<_Tp> first_argument_type;
531  typedef experimental::propagate_const<_Tp> second_argument_type;
532  typedef bool result_type;
533  };
534 
535 _GLIBCXX_END_NAMESPACE_VERSION
536 } // namespace std
537 
538 #endif // C++14
539 
540 #endif // _GLIBCXX_EXPERIMENTAL_PROPAGATE_CONST