Horizon
Loading...
Searching...
No Matches
box.hpp
Go to the documentation of this file.
1
2// 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
27
29
30#include <range/v3/detail/prologue.hpp>
31
32RANGES_DIAGNOSTIC_PUSH
33RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
34
35namespace 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
366RANGES_DIAGNOSTIC_POP
367
368#include <range/v3/detail/epilogue.hpp>
369
370#endif
@ none
No concepts met.
Definition box.hpp:163
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
Tiny meta-programming library.
Definition meta.hpp:1383