Horizon
box.hpp
Go to the documentation of this file.
1 // Range v3 library
3 //
4 // Copyright Eric Niebler 2013-present
5 // Copyright Casey Carter 2016
6 //
7 // Use, modification and distribution is subject to the
8 // Boost Software License, Version 1.0. (See accompanying
9 // file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt)
11 //
12 // Project home: https://github.com/ericniebler/range-v3
13 //
14 
15 #ifndef RANGES_V3_UTILITY_BOX_HPP
16 #define RANGES_V3_UTILITY_BOX_HPP
17 
18 #include <cstdlib>
19 #include <type_traits>
20 #include <utility>
21 
22 #include <meta/meta.hpp>
23 
24 #include <concepts/concepts.hpp>
25 
26 #include <range/v3/range_fwd.hpp>
27 
28 #include <range/v3/utility/get.hpp>
29 
30 #include <range/v3/detail/prologue.hpp>
31 
32 RANGES_DIAGNOSTIC_PUSH
33 RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
34 
35 namespace ranges
36 {
40 
42  template<typename T>
43  struct RANGES_DEPRECATED("The ranges::mutable_ class template is deprecated") mutable_
44  {
45  mutable T value;
46 
47  CPP_member
48  constexpr CPP_ctor(mutable_)()(
49  requires std::is_default_constructible<T>::value)
50  : value{}
51  {}
52  constexpr explicit mutable_(T const & t)
53  : value(t)
54  {}
55  constexpr explicit mutable_(T && t)
56  : value(detail::move(t))
57  {}
58  mutable_ const & operator=(T const & t) const
59  {
60  value = t;
61  return *this;
62  }
63  mutable_ const & operator=(T && t) const
64  {
65  value = detail::move(t);
66  return *this;
67  }
68  constexpr operator T &() const &
69  {
70  return value;
71  }
72  };
73 
74  template<typename T, T v>
75  struct RANGES_DEPRECATED("The ranges::constant class template is deprecated") constant
76  {
77  constant() = default;
78  constexpr explicit constant(T const &)
79  {}
80  constant & operator=(T const &)
81  {
82  return *this;
83  }
84  constant const & operator=(T const &) const
85  {
86  return *this;
87  }
88  constexpr operator T() const
89  {
90  return v;
91  }
92  constexpr T exchange(T const &) const
93  {
94  return v;
95  }
96  };
98 
100  namespace detail
101  {
102  // "box" has three different implementations that store a T differently:
103  enum class box_compress
104  {
105  none, // Nothing special: get() returns a reference to a T member subobject
106  ebo, // Apply Empty Base Optimization: get() returns a reference to a T base
107  // subobject
108  coalesce // Coalesce all Ts into one T: get() returns a reference to a static
109  // T singleton
110  };
111 
112  // Per N4582, lambda closures are *not*:
113  // - aggregates ([expr.prim.lambda]/4)
114  // - default constructible_from ([expr.prim.lambda]/p21)
115  // - copy assignable ([expr.prim.lambda]/p21)
116  template<typename Fn>
118  !std::is_copy_assignable<Fn>::value>;
119 
120  template<typename>
121  constexpr box_compress box_compression_(...)
122  {
123  return box_compress::none;
124  }
125  template<typename T, typename = meta::if_<meta::strict_and<
126  std::is_empty<T>,
128 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 6 && __GNUC_MINOR__ < 2
129  // GCC 6.0 & 6.1 find empty lambdas' implicit conversion
130  // to function pointer when doing overload resolution
131  // for function calls. That causes hard errors.
132  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71117
133  ,
135 #endif
136  >>>
137  constexpr box_compress box_compression_(long)
138  {
139  return box_compress::ebo;
140  }
141 #ifndef RANGES_WORKAROUND_MSVC_249830
142  // MSVC pukes passing non-constant-expression objects to constexpr
143  // functions, so do not coalesce.
144  template<typename T,
145  typename =
146  meta::if_<meta::strict_and<std::is_empty<T>, detail::is_trivial<T>>>>
147  constexpr box_compress box_compression_(int)
148  {
149  return box_compress::coalesce;
150  }
151 #endif
152  template<typename T>
153  constexpr box_compress box_compression()
154  {
155  return box_compression_<T>(0);
156  }
157  } // namespace detail
159 
160  template<typename Element, typename Tag = void,
161  detail::box_compress = detail::box_compression<Element>()>
162  class box
163  {
164  Element value;
165 
166  public:
167  CPP_member
168  constexpr CPP_ctor(box)()( //
169  noexcept(std::is_nothrow_default_constructible<Element>::value) //
170  requires std::is_default_constructible<Element>::value)
171  : value{}
172  {}
173 #if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
174  template(typename E)(
175  requires (!same_as<box, detail::decay_t<E>>) AND
176  constructible_from<Element, E>)
177  constexpr explicit(!convertible_to<E, Element>) box(E && e)
178  noexcept(std::is_nothrow_constructible<Element, E>::value) //
179  : value(static_cast<E &&>(e))
180  {}
181 #else
182  template(typename E)(
183  requires (!same_as<box, detail::decay_t<E>>) AND
184  constructible_from<Element, E> AND
185  convertible_to<E, Element>)
186  constexpr box(E && e)
187  noexcept(std::is_nothrow_constructible<Element, E>::value)
188  : value(static_cast<E &&>(e))
189  {}
190  template(typename E)(
191  requires (!same_as<box, detail::decay_t<E>>) AND
192  constructible_from<Element, E> AND
193  (!convertible_to<E, Element>))
194  constexpr explicit box(E && e)
195  noexcept(std::is_nothrow_constructible<Element, E>::value) //
196  : value(static_cast<E &&>(e))
197  {}
198 #endif
199 
200  constexpr Element & get() & noexcept
201  {
202  return value;
203  }
204  constexpr Element const & get() const & noexcept
205  {
206  return value;
207  }
208  constexpr Element && get() && noexcept
209  {
210  return detail::move(value);
211  }
212  constexpr Element const && get() const && noexcept
213  {
214  return detail::move(value);
215  }
216  };
217 
218  template<typename Element, typename Tag>
220  {
221  public:
222  CPP_member
223  constexpr CPP_ctor(box)()( //
224  noexcept(std::is_nothrow_default_constructible<Element>::value) //
225  requires std::is_default_constructible<Element>::value)
226  : Element{}
227  {}
228 #if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
229  template(typename E)(
230  requires (!same_as<box, detail::decay_t<E>>) AND
231  constructible_from<Element, E>)
232  constexpr explicit(!convertible_to<E, Element>) box(E && e)
233  noexcept(std::is_nothrow_constructible<Element, E>::value) //
234  : Element(static_cast<E &&>(e))
235  {}
236 #else
237  template(typename E)(
238  requires (!same_as<box, detail::decay_t<E>>) AND
239  constructible_from<Element, E> AND
240  convertible_to<E, Element>)
241  constexpr box(E && e)
242  noexcept(std::is_nothrow_constructible<Element, E>::value) //
243  : Element(static_cast<E &&>(e))
244  {}
245  template(typename E)(
246  requires (!same_as<box, detail::decay_t<E>>) AND
247  constructible_from<Element, E> AND
248  (!convertible_to<E, Element>))
249  constexpr explicit box(E && e)
250  noexcept(std::is_nothrow_constructible<Element, E>::value) //
251  : Element(static_cast<E &&>(e))
252  {}
253 #endif
254 
255  constexpr Element & get() & noexcept
256  {
257  return *this;
258  }
259  constexpr Element const & get() const & noexcept
260  {
261  return *this;
262  }
263  constexpr Element && get() && noexcept
264  {
265  return detail::move(*this);
266  }
267  constexpr Element const && get() const && noexcept
268  {
269  return detail::move(*this);
270  }
271  };
272 
273  template<typename Element, typename Tag>
275  {
276  static Element value;
277 
278  public:
279  constexpr box() noexcept = default;
280 
281 #if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
282  template(typename E)(
283  requires (!same_as<box, detail::decay_t<E>>) AND
284  constructible_from<Element, E>)
285  constexpr explicit(!convertible_to<E, Element>) box(E &&) noexcept
286  {}
287 #else
288  template(typename E)(
289  requires (!same_as<box, detail::decay_t<E>>) AND
290  constructible_from<Element, E> AND
291  convertible_to<E, Element>)
292  constexpr box(E &&) noexcept
293  {}
294  template(typename E)(
295  requires (!same_as<box, detail::decay_t<E>>) AND
296  constructible_from<Element, E> AND
297  (!convertible_to<E, Element>))
298  constexpr explicit box(E &&) noexcept
299  {}
300 #endif
301 
302  constexpr Element & get() & noexcept
303  {
304  return value;
305  }
306  constexpr Element const & get() const & noexcept
307  {
308  return value;
309  }
310  constexpr Element && get() && noexcept
311  {
312  return detail::move(value);
313  }
314  constexpr Element const && get() const && noexcept
315  {
316  return detail::move(value);
317  }
318  };
319 
320  template<typename Element, typename Tag>
322 
324  namespace _get_
325  {
327  // Get by tag type
328  template<typename Tag, typename Element, detail::box_compress BC>
329  constexpr Element & get(box<Element, Tag, BC> & b) noexcept
330  {
331  return b.get();
332  }
333  template<typename Tag, typename Element, detail::box_compress BC>
334  constexpr Element const & get(box<Element, Tag, BC> const & b) noexcept
335  {
336  return b.get();
337  }
338  template<typename Tag, typename Element, detail::box_compress BC>
339  constexpr Element && get(box<Element, Tag, BC> && b) noexcept
340  {
341  return detail::move(b).get();
342  }
343  // Get by index
344  template<std::size_t I, typename Element, detail::box_compress BC>
345  constexpr Element & get(box<Element, meta::size_t<I>, BC> & b) noexcept
346  {
347  return b.get();
348  }
349  template<std::size_t I, typename Element, detail::box_compress BC>
350  constexpr Element const & get(
351  box<Element, meta::size_t<I>, BC> const & b) noexcept
352  {
353  return b.get();
354  }
355  template<std::size_t I, typename Element, detail::box_compress BC>
356  constexpr Element && get(box<Element, meta::size_t<I>, BC> && b) noexcept
357  {
358  return detail::move(b).get();
359  }
361  } // namespace _get_
364 } // namespace ranges
365 
366 RANGES_DIAGNOSTIC_POP
367 
368 #include <range/v3/detail/epilogue.hpp>
369 
370 #endif
@ none
No concepts met.
Definition: box.hpp:163
template(typename ActionFn, typename Rng)(concept(invocable_action_closure_)(ActionFn
\concept invocable_action_closure_
std::integral_constant< bool, B > bool_
An integral constant wrapper for bool.
Definition: meta.hpp:168
std::integral_constant< std::size_t, N > size_t
An integral constant wrapper for std::size_t.
Definition: meta.hpp:163
_t< detail::_if_< list< Args... > >> if_
Select one type or another depending on a compile-time Boolean.
Definition: meta.hpp:1247
not_c< B::type::value > not_
Logically negate the integral constant-wrapped Boolean parameter.
Definition: meta.hpp:1357
_t< detail::is_< T, C > > is
is
Definition: meta.hpp:874
Tiny meta-programming library.
Definition: meta.hpp:1383