]>
Commit | Line | Data |
---|---|---|
2b5ab1e4 MB |
1 | // <optional> -*- C++ -*- |
2 | ||
cbe34bb5 | 3 | // Copyright (C) 2013-2017 Free Software Foundation, Inc. |
2b5ab1e4 MB |
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/optional | |
26 | * This is a TS C++ Library header. | |
27 | */ | |
28 | ||
29 | #ifndef _GLIBCXX_EXPERIMENTAL_OPTIONAL | |
30 | #define _GLIBCXX_EXPERIMENTAL_OPTIONAL 1 | |
31 | ||
32 | /** | |
33 | * @defgroup experimental Experimental | |
34 | * | |
35 | * Components specified by various Technical Specifications. | |
6b4f8906 JW |
36 | * |
37 | * As indicated by the std::experimental namespace and the header paths, | |
38 | * the contents of these Technical Specifications are experimental and not | |
39 | * part of the C++ standard. As such the interfaces and implementations may | |
40 | * change in the future, and there is <STRONG> no guarantee of compatibility | |
41 | * between different GCC releases </STRONG> for these features. | |
2b5ab1e4 MB |
42 | */ |
43 | ||
44 | #if __cplusplus <= 201103L | |
45 | # include <bits/c++14_warning.h> | |
46 | #else | |
47 | ||
48 | #include <utility> | |
49 | #include <type_traits> | |
50 | #include <stdexcept> | |
51 | #include <new> | |
52 | #include <initializer_list> | |
53 | #include <bits/functexcept.h> | |
54 | #include <bits/functional_hash.h> | |
55 | #include <bits/enable_special_members.h> | |
e347987d | 56 | #include <experimental/bits/lfts_config.h> |
2b5ab1e4 MB |
57 | |
58 | namespace std _GLIBCXX_VISIBILITY(default) | |
59 | { | |
4a15d842 FD |
60 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
61 | ||
2b5ab1e4 MB |
62 | namespace experimental |
63 | { | |
7ce56fc8 JW |
64 | inline namespace fundamentals_v1 |
65 | { | |
2b5ab1e4 MB |
66 | /** |
67 | * @defgroup optional Optional values | |
68 | * @ingroup experimental | |
69 | * | |
70 | * Class template for optional values and surrounding facilities, as | |
71 | * described in n3793 "A proposal to add a utility class to represent | |
72 | * optional objects (Revision 5)". | |
73 | * | |
74 | * @{ | |
75 | */ | |
76 | ||
65545817 | 77 | #define __cpp_lib_experimental_optional 201411 |
c2513a1f | 78 | |
2b5ab1e4 MB |
79 | // All subsequent [X.Y.n] references are against n3793. |
80 | ||
81 | // [X.Y.4] | |
82 | template<typename _Tp> | |
83 | class optional; | |
84 | ||
85 | // [X.Y.5] | |
86 | /// Tag type for in-place construction. | |
87 | struct in_place_t { }; | |
88 | ||
89 | /// Tag for in-place construction. | |
90 | constexpr in_place_t in_place { }; | |
91 | ||
92 | // [X.Y.6] | |
93 | /// Tag type to disengage optional objects. | |
94 | struct nullopt_t | |
95 | { | |
96 | // Do not user-declare default constructor at all for | |
97 | // optional_value = {} syntax to work. | |
98 | // nullopt_t() = delete; | |
99 | ||
100 | // Used for constructing nullopt. | |
101 | enum class _Construct { _Token }; | |
102 | ||
103 | // Must be constexpr for nullopt_t to be literal. | |
104 | explicit constexpr nullopt_t(_Construct) { } | |
105 | }; | |
106 | ||
107 | // [X.Y.6] | |
108 | /// Tag to disengage optional objects. | |
109 | constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token }; | |
110 | ||
111 | // [X.Y.7] | |
112 | /** | |
113 | * @brief Exception class thrown when a disengaged optional object is | |
114 | * dereferenced. | |
115 | * @ingroup exceptions | |
116 | */ | |
117 | class bad_optional_access : public logic_error | |
118 | { | |
119 | public: | |
4159cf0d | 120 | bad_optional_access() : logic_error("bad optional access") { } |
2b5ab1e4 | 121 | |
4159cf0d | 122 | // XXX This constructor is non-standard. Should not be inline |
2b5ab1e4 MB |
123 | explicit bad_optional_access(const char* __arg) : logic_error(__arg) { } |
124 | ||
125 | virtual ~bad_optional_access() noexcept = default; | |
126 | }; | |
127 | ||
128 | void | |
129 | __throw_bad_optional_access(const char*) | |
130 | __attribute__((__noreturn__)); | |
131 | ||
132 | // XXX Does not belong here. | |
133 | inline void | |
134 | __throw_bad_optional_access(const char* __s) | |
135 | { _GLIBCXX_THROW_OR_ABORT(bad_optional_access(__s)); } | |
136 | ||
1637d425 | 137 | #ifndef __cpp_lib_addressof_constexpr |
72e58f18 JW |
138 | template<typename _Tp, typename = void> |
139 | struct _Has_addressof_mem : std::false_type { }; | |
2b5ab1e4 MB |
140 | |
141 | template<typename _Tp> | |
72e58f18 JW |
142 | struct _Has_addressof_mem<_Tp, |
143 | __void_t<decltype( std::declval<const _Tp&>().operator&() )> | |
144 | > | |
145 | : std::true_type { }; | |
146 | ||
147 | template<typename _Tp, typename = void> | |
148 | struct _Has_addressof_free : std::false_type { }; | |
149 | ||
150 | template<typename _Tp> | |
151 | struct _Has_addressof_free<_Tp, | |
152 | __void_t<decltype( operator&(std::declval<const _Tp&>()) )> | |
153 | > | |
154 | : std::true_type { }; | |
2b5ab1e4 MB |
155 | |
156 | /** | |
157 | * @brief Trait that detects the presence of an overloaded unary operator&. | |
158 | * | |
159 | * Practically speaking this detects the presence of such an operator when | |
86c0ec1d VV |
160 | * called on a const-qualified lvalue (e.g. |
161 | * declval<const _Tp&>().operator&()). | |
2b5ab1e4 MB |
162 | */ |
163 | template<typename _Tp> | |
72e58f18 JW |
164 | struct _Has_addressof |
165 | : std::__or_<_Has_addressof_mem<_Tp>, _Has_addressof_free<_Tp>>::type | |
166 | { }; | |
2b5ab1e4 MB |
167 | |
168 | /** | |
169 | * @brief An overload that attempts to take the address of an lvalue as a | |
170 | * constant expression. Falls back to __addressof in the presence of an | |
171 | * overloaded addressof operator (unary operator&), in which case the call | |
172 | * will not be a constant expression. | |
173 | */ | |
1637d425 VV |
174 | template<typename _Tp> |
175 | constexpr | |
176 | enable_if_t<!_Has_addressof<_Tp>::value, _Tp*> | |
177 | __constexpr_addressof(_Tp& __t) | |
2b5ab1e4 MB |
178 | { return &__t; } |
179 | ||
180 | /** | |
181 | * @brief Fallback overload that defers to __addressof. | |
182 | */ | |
1637d425 VV |
183 | template<typename _Tp> |
184 | inline | |
185 | enable_if_t<_Has_addressof<_Tp>::value, _Tp*> | |
186 | __constexpr_addressof(_Tp& __t) | |
2b5ab1e4 | 187 | { return std::__addressof(__t); } |
1637d425 | 188 | #endif // __cpp_lib_addressof_constexpr |
2b5ab1e4 MB |
189 | |
190 | /** | |
191 | * @brief Class template that holds the necessary state for @ref optional | |
192 | * and that has the responsibility for construction and the special members. | |
193 | * | |
194 | * Such a separate base class template is necessary in order to | |
195 | * conditionally enable the special members (e.g. copy/move constructors). | |
196 | * Note that this means that @ref _Optional_base implements the | |
197 | * functionality for copy and move assignment, but not for converting | |
198 | * assignment. | |
199 | * | |
200 | * @see optional, _Enable_special_members | |
201 | */ | |
202 | template<typename _Tp, bool _ShouldProvideDestructor = | |
203 | !is_trivially_destructible<_Tp>::value> | |
204 | class _Optional_base | |
205 | { | |
206 | private: | |
207 | // Remove const to avoid prohibition of reusing object storage for | |
208 | // const-qualified types in [3.8/9]. This is strictly internal | |
209 | // and even optional itself is oblivious to it. | |
8a57bed1 | 210 | using _Stored_type = remove_const_t<_Tp>; |
2b5ab1e4 MB |
211 | |
212 | public: | |
213 | // [X.Y.4.1] Constructors. | |
214 | ||
215 | // Constructors for disengaged optionals. | |
216 | constexpr _Optional_base() noexcept | |
217 | : _M_empty{} { } | |
218 | ||
219 | constexpr _Optional_base(nullopt_t) noexcept | |
220 | : _Optional_base{} { } | |
221 | ||
222 | // Constructors for engaged optionals. | |
2b5ab1e4 MB |
223 | template<typename... _Args> |
224 | constexpr explicit _Optional_base(in_place_t, _Args&&... __args) | |
225 | : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { } | |
226 | ||
227 | template<typename _Up, typename... _Args, | |
8a57bed1 JW |
228 | enable_if_t<is_constructible<_Tp, |
229 | initializer_list<_Up>&, | |
230 | _Args&&...>::value, | |
231 | int>...> | |
2b5ab1e4 MB |
232 | constexpr explicit _Optional_base(in_place_t, |
233 | initializer_list<_Up> __il, | |
234 | _Args&&... __args) | |
235 | : _M_payload(__il, std::forward<_Args>(__args)...), | |
236 | _M_engaged(true) { } | |
237 | ||
238 | // Copy and move constructors. | |
239 | _Optional_base(const _Optional_base& __other) | |
240 | { | |
241 | if (__other._M_engaged) | |
242 | this->_M_construct(__other._M_get()); | |
243 | } | |
244 | ||
245 | _Optional_base(_Optional_base&& __other) | |
246 | noexcept(is_nothrow_move_constructible<_Tp>()) | |
247 | { | |
248 | if (__other._M_engaged) | |
249 | this->_M_construct(std::move(__other._M_get())); | |
250 | } | |
251 | ||
252 | // [X.Y.4.3] (partly) Assignment. | |
253 | _Optional_base& | |
254 | operator=(const _Optional_base& __other) | |
255 | { | |
256 | if (this->_M_engaged && __other._M_engaged) | |
257 | this->_M_get() = __other._M_get(); | |
258 | else | |
b1705a63 JW |
259 | { |
260 | if (__other._M_engaged) | |
261 | this->_M_construct(__other._M_get()); | |
262 | else | |
263 | this->_M_reset(); | |
264 | } | |
2b5ab1e4 MB |
265 | |
266 | return *this; | |
267 | } | |
268 | ||
269 | _Optional_base& | |
270 | operator=(_Optional_base&& __other) | |
b1705a63 JW |
271 | noexcept(__and_<is_nothrow_move_constructible<_Tp>, |
272 | is_nothrow_move_assignable<_Tp>>()) | |
2b5ab1e4 | 273 | { |
b1705a63 JW |
274 | if (this->_M_engaged && __other._M_engaged) |
275 | this->_M_get() = std::move(__other._M_get()); | |
276 | else | |
277 | { | |
278 | if (__other._M_engaged) | |
279 | this->_M_construct(std::move(__other._M_get())); | |
280 | else | |
281 | this->_M_reset(); | |
282 | } | |
283 | return *this; | |
2b5ab1e4 MB |
284 | } |
285 | ||
286 | // [X.Y.4.2] Destructor. | |
287 | ~_Optional_base() | |
288 | { | |
289 | if (this->_M_engaged) | |
290 | this->_M_payload.~_Stored_type(); | |
291 | } | |
292 | ||
293 | // The following functionality is also needed by optional, hence the | |
294 | // protected accessibility. | |
295 | protected: | |
296 | constexpr bool _M_is_engaged() const noexcept | |
297 | { return this->_M_engaged; } | |
298 | ||
299 | // The _M_get operations have _M_engaged as a precondition. | |
65545817 | 300 | constexpr _Tp& |
2b5ab1e4 MB |
301 | _M_get() noexcept |
302 | { return _M_payload; } | |
303 | ||
304 | constexpr const _Tp& | |
305 | _M_get() const noexcept | |
306 | { return _M_payload; } | |
307 | ||
308 | // The _M_construct operation has !_M_engaged as a precondition | |
309 | // while _M_destruct has _M_engaged as a precondition. | |
310 | template<typename... _Args> | |
311 | void | |
312 | _M_construct(_Args&&... __args) | |
313 | noexcept(is_nothrow_constructible<_Stored_type, _Args...>()) | |
314 | { | |
315 | ::new (std::__addressof(this->_M_payload)) | |
316 | _Stored_type(std::forward<_Args>(__args)...); | |
317 | this->_M_engaged = true; | |
318 | } | |
319 | ||
320 | void | |
321 | _M_destruct() | |
322 | { | |
323 | this->_M_engaged = false; | |
324 | this->_M_payload.~_Stored_type(); | |
325 | } | |
326 | ||
327 | // _M_reset is a 'safe' operation with no precondition. | |
328 | void | |
329 | _M_reset() | |
330 | { | |
331 | if (this->_M_engaged) | |
332 | this->_M_destruct(); | |
333 | } | |
334 | ||
335 | private: | |
336 | struct _Empty_byte { }; | |
337 | union { | |
338 | _Empty_byte _M_empty; | |
339 | _Stored_type _M_payload; | |
340 | }; | |
341 | bool _M_engaged = false; | |
342 | }; | |
343 | ||
344 | /// Partial specialization that is exactly identical to the primary template | |
345 | /// save for not providing a destructor, to fulfill triviality requirements. | |
346 | template<typename _Tp> | |
347 | class _Optional_base<_Tp, false> | |
348 | { | |
349 | private: | |
8a57bed1 | 350 | using _Stored_type = remove_const_t<_Tp>; |
2b5ab1e4 MB |
351 | |
352 | public: | |
353 | constexpr _Optional_base() noexcept | |
354 | : _M_empty{} { } | |
355 | ||
356 | constexpr _Optional_base(nullopt_t) noexcept | |
357 | : _Optional_base{} { } | |
358 | ||
2b5ab1e4 MB |
359 | template<typename... _Args> |
360 | constexpr explicit _Optional_base(in_place_t, _Args&&... __args) | |
361 | : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { } | |
362 | ||
363 | template<typename _Up, typename... _Args, | |
8a57bed1 JW |
364 | enable_if_t<is_constructible<_Tp, |
365 | initializer_list<_Up>&, | |
366 | _Args&&...>::value, | |
367 | int>...> | |
2b5ab1e4 MB |
368 | constexpr explicit _Optional_base(in_place_t, |
369 | initializer_list<_Up> __il, | |
370 | _Args&&... __args) | |
371 | : _M_payload(__il, std::forward<_Args>(__args)...), | |
372 | _M_engaged(true) { } | |
373 | ||
374 | _Optional_base(const _Optional_base& __other) | |
375 | { | |
376 | if (__other._M_engaged) | |
377 | this->_M_construct(__other._M_get()); | |
378 | } | |
379 | ||
380 | _Optional_base(_Optional_base&& __other) | |
381 | noexcept(is_nothrow_move_constructible<_Tp>()) | |
382 | { | |
383 | if (__other._M_engaged) | |
384 | this->_M_construct(std::move(__other._M_get())); | |
385 | } | |
386 | ||
387 | _Optional_base& | |
388 | operator=(const _Optional_base& __other) | |
389 | { | |
b1705a63 JW |
390 | if (this->_M_engaged && __other._M_engaged) |
391 | this->_M_get() = __other._M_get(); | |
392 | else | |
393 | { | |
394 | if (__other._M_engaged) | |
395 | this->_M_construct(__other._M_get()); | |
396 | else | |
397 | this->_M_reset(); | |
398 | } | |
399 | return *this; | |
2b5ab1e4 MB |
400 | } |
401 | ||
402 | _Optional_base& | |
403 | operator=(_Optional_base&& __other) | |
b1705a63 JW |
404 | noexcept(__and_<is_nothrow_move_constructible<_Tp>, |
405 | is_nothrow_move_assignable<_Tp>>()) | |
2b5ab1e4 | 406 | { |
b1705a63 JW |
407 | if (this->_M_engaged && __other._M_engaged) |
408 | this->_M_get() = std::move(__other._M_get()); | |
409 | else | |
410 | { | |
411 | if (__other._M_engaged) | |
412 | this->_M_construct(std::move(__other._M_get())); | |
413 | else | |
414 | this->_M_reset(); | |
415 | } | |
416 | return *this; | |
2b5ab1e4 MB |
417 | } |
418 | ||
419 | // Sole difference | |
420 | // ~_Optional_base() noexcept = default; | |
421 | ||
422 | protected: | |
423 | constexpr bool _M_is_engaged() const noexcept | |
424 | { return this->_M_engaged; } | |
425 | ||
426 | _Tp& | |
427 | _M_get() noexcept | |
428 | { return _M_payload; } | |
429 | ||
430 | constexpr const _Tp& | |
431 | _M_get() const noexcept | |
432 | { return _M_payload; } | |
433 | ||
434 | template<typename... _Args> | |
435 | void | |
436 | _M_construct(_Args&&... __args) | |
437 | noexcept(is_nothrow_constructible<_Stored_type, _Args...>()) | |
438 | { | |
439 | ::new (std::__addressof(this->_M_payload)) | |
440 | _Stored_type(std::forward<_Args>(__args)...); | |
441 | this->_M_engaged = true; | |
442 | } | |
443 | ||
444 | void | |
445 | _M_destruct() | |
446 | { | |
447 | this->_M_engaged = false; | |
448 | this->_M_payload.~_Stored_type(); | |
449 | } | |
450 | ||
451 | void | |
452 | _M_reset() | |
453 | { | |
454 | if (this->_M_engaged) | |
455 | this->_M_destruct(); | |
456 | } | |
457 | ||
458 | private: | |
459 | struct _Empty_byte { }; | |
b1705a63 JW |
460 | union |
461 | { | |
462 | _Empty_byte _M_empty; | |
463 | _Stored_type _M_payload; | |
2b5ab1e4 MB |
464 | }; |
465 | bool _M_engaged = false; | |
466 | }; | |
467 | ||
6ffe8548 VV |
468 | template<typename _Tp> |
469 | class optional; | |
470 | ||
f11cc050 VV |
471 | template<typename _Tp, typename _Up> |
472 | using __converts_from_optional = | |
473 | __or_<is_constructible<_Tp, const optional<_Up>&>, | |
474 | is_constructible<_Tp, optional<_Up>&>, | |
475 | is_constructible<_Tp, const optional<_Up>&&>, | |
476 | is_constructible<_Tp, optional<_Up>&&>, | |
477 | is_convertible<const optional<_Up>&, _Tp>, | |
478 | is_convertible<optional<_Up>&, _Tp>, | |
479 | is_convertible<const optional<_Up>&&, _Tp>, | |
480 | is_convertible<optional<_Up>&&, _Tp>>; | |
481 | ||
482 | template<typename _Tp, typename _Up> | |
483 | using __assigns_from_optional = | |
484 | __or_<is_assignable<_Tp&, const optional<_Up>&>, | |
485 | is_assignable<_Tp&, optional<_Up>&>, | |
486 | is_assignable<_Tp&, const optional<_Up>&&>, | |
487 | is_assignable<_Tp&, optional<_Up>&&>>; | |
6ffe8548 | 488 | |
2b5ab1e4 MB |
489 | /** |
490 | * @brief Class template for optional values. | |
491 | */ | |
492 | template<typename _Tp> | |
493 | class optional | |
494 | : private _Optional_base<_Tp>, | |
495 | private _Enable_copy_move< | |
496 | // Copy constructor. | |
497 | is_copy_constructible<_Tp>::value, | |
498 | // Copy assignment. | |
b1705a63 | 499 | __and_<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>::value, |
2b5ab1e4 MB |
500 | // Move constructor. |
501 | is_move_constructible<_Tp>::value, | |
502 | // Move assignment. | |
b1705a63 | 503 | __and_<is_move_constructible<_Tp>, is_move_assignable<_Tp>>::value, |
2b5ab1e4 MB |
504 | // Unique tag type. |
505 | optional<_Tp>> | |
506 | { | |
8a57bed1 JW |
507 | static_assert(__and_<__not_<is_same<remove_cv_t<_Tp>, nullopt_t>>, |
508 | __not_<is_same<remove_cv_t<_Tp>, in_place_t>>, | |
b1705a63 JW |
509 | __not_<is_reference<_Tp>>>(), |
510 | "Invalid instantiation of optional<T>"); | |
2b5ab1e4 MB |
511 | |
512 | private: | |
513 | using _Base = _Optional_base<_Tp>; | |
514 | ||
515 | public: | |
516 | using value_type = _Tp; | |
517 | ||
518 | // _Optional_base has the responsibility for construction. | |
519 | using _Base::_Base; | |
520 | ||
6ffe8548 VV |
521 | constexpr optional() = default; |
522 | // Converting constructors for engaged optionals. | |
f11cc050 | 523 | template <typename _Up = _Tp, |
6ffe8548 | 524 | enable_if_t<__and_< |
f11cc050 | 525 | __not_<is_same<optional<_Tp>, decay_t<_Up>>>, |
6ffe8548 VV |
526 | is_constructible<_Tp, _Up&&>, |
527 | is_convertible<_Up&&, _Tp> | |
528 | >::value, bool> = true> | |
529 | constexpr optional(_Up&& __t) | |
f11cc050 | 530 | : _Base(in_place, std::forward<_Up>(__t)) { } |
6ffe8548 | 531 | |
f11cc050 | 532 | template <typename _Up = _Tp, |
6ffe8548 | 533 | enable_if_t<__and_< |
f11cc050 VV |
534 | __not_<is_same<optional<_Tp>, decay_t<_Up>>>, |
535 | is_constructible<_Tp, _Up&&>, | |
536 | __not_<is_convertible<_Up&&, _Tp>> | |
537 | >::value, bool> = false> | |
6ffe8548 | 538 | explicit constexpr optional(_Up&& __t) |
f11cc050 | 539 | : _Base(in_place, std::forward<_Up>(__t)) { } |
6ffe8548 VV |
540 | |
541 | template <typename _Up, | |
542 | enable_if_t<__and_< | |
543 | __not_<is_same<_Tp, _Up>>, | |
6ffe8548 | 544 | is_constructible<_Tp, const _Up&>, |
f11cc050 VV |
545 | is_convertible<const _Up&, _Tp>, |
546 | __not_<__converts_from_optional<_Tp, _Up>> | |
6ffe8548 VV |
547 | >::value, bool> = true> |
548 | constexpr optional(const optional<_Up>& __t) | |
f11cc050 VV |
549 | { |
550 | if (__t) | |
551 | emplace(*__t); | |
552 | } | |
6ffe8548 VV |
553 | |
554 | template <typename _Up, | |
555 | enable_if_t<__and_< | |
556 | __not_<is_same<_Tp, _Up>>, | |
6ffe8548 | 557 | is_constructible<_Tp, const _Up&>, |
f11cc050 VV |
558 | __not_<is_convertible<const _Up&, _Tp>>, |
559 | __not_<__converts_from_optional<_Tp, _Up>> | |
6ffe8548 VV |
560 | >::value, bool> = false> |
561 | explicit constexpr optional(const optional<_Up>& __t) | |
f11cc050 VV |
562 | { |
563 | if (__t) | |
564 | emplace(*__t); | |
565 | } | |
6ffe8548 VV |
566 | |
567 | template <typename _Up, | |
568 | enable_if_t<__and_< | |
569 | __not_<is_same<_Tp, _Up>>, | |
6ffe8548 | 570 | is_constructible<_Tp, _Up&&>, |
f11cc050 VV |
571 | is_convertible<_Up&&, _Tp>, |
572 | __not_<__converts_from_optional<_Tp, _Up>> | |
6ffe8548 VV |
573 | >::value, bool> = true> |
574 | constexpr optional(optional<_Up>&& __t) | |
f11cc050 VV |
575 | { |
576 | if (__t) | |
577 | emplace(std::move(*__t)); | |
578 | } | |
6ffe8548 VV |
579 | |
580 | template <typename _Up, | |
581 | enable_if_t<__and_< | |
582 | __not_<is_same<_Tp, _Up>>, | |
6ffe8548 | 583 | is_constructible<_Tp, _Up&&>, |
f11cc050 VV |
584 | __not_<is_convertible<_Up&&, _Tp>>, |
585 | __not_<__converts_from_optional<_Tp, _Up>> | |
6ffe8548 VV |
586 | >::value, bool> = false> |
587 | explicit constexpr optional(optional<_Up>&& __t) | |
f11cc050 VV |
588 | { |
589 | if (__t) | |
590 | emplace(std::move(*__t)); | |
591 | } | |
6ffe8548 | 592 | |
2b5ab1e4 MB |
593 | // [X.Y.4.3] (partly) Assignment. |
594 | optional& | |
595 | operator=(nullopt_t) noexcept | |
596 | { | |
597 | this->_M_reset(); | |
598 | return *this; | |
599 | } | |
600 | ||
f11cc050 VV |
601 | template<typename _Up = _Tp> |
602 | enable_if_t<__and_< | |
603 | __not_<is_same<optional<_Tp>, decay_t<_Up>>>, | |
604 | is_constructible<_Tp, _Up>, | |
605 | __not_<__and_<is_scalar<_Tp>, | |
606 | is_same<_Tp, decay_t<_Up>>>>, | |
607 | is_assignable<_Tp&, _Up>>::value, | |
608 | optional&> | |
2b5ab1e4 MB |
609 | operator=(_Up&& __u) |
610 | { | |
2b5ab1e4 MB |
611 | if (this->_M_is_engaged()) |
612 | this->_M_get() = std::forward<_Up>(__u); | |
613 | else | |
614 | this->_M_construct(std::forward<_Up>(__u)); | |
615 | ||
616 | return *this; | |
617 | } | |
618 | ||
f11cc050 VV |
619 | template<typename _Up> |
620 | enable_if_t<__and_< | |
621 | __not_<is_same<_Tp, _Up>>, | |
622 | is_constructible<_Tp, const _Up&>, | |
623 | is_assignable<_Tp&, _Up>, | |
624 | __not_<__converts_from_optional<_Tp, _Up>>, | |
625 | __not_<__assigns_from_optional<_Tp, _Up>> | |
626 | >::value, | |
627 | optional&> | |
6ffe8548 VV |
628 | operator=(const optional<_Up>& __u) |
629 | { | |
6ffe8548 VV |
630 | if (__u) |
631 | { | |
632 | if (this->_M_is_engaged()) | |
633 | this->_M_get() = *__u; | |
634 | else | |
635 | this->_M_construct(*__u); | |
636 | } | |
637 | else | |
638 | { | |
639 | this->_M_reset(); | |
640 | } | |
641 | return *this; | |
642 | } | |
643 | ||
f11cc050 VV |
644 | template<typename _Up> |
645 | enable_if_t<__and_< | |
646 | __not_<is_same<_Tp, _Up>>, | |
647 | is_constructible<_Tp, _Up>, | |
648 | is_assignable<_Tp&, _Up>, | |
649 | __not_<__converts_from_optional<_Tp, _Up>>, | |
650 | __not_<__assigns_from_optional<_Tp, _Up>> | |
651 | >::value, | |
652 | optional&> | |
6ffe8548 VV |
653 | operator=(optional<_Up>&& __u) |
654 | { | |
6ffe8548 VV |
655 | if (__u) |
656 | { | |
657 | if (this->_M_is_engaged()) | |
658 | this->_M_get() = std::move(*__u); | |
659 | else | |
660 | this->_M_construct(std::move(*__u)); | |
661 | } | |
662 | else | |
663 | { | |
664 | this->_M_reset(); | |
665 | } | |
666 | ||
667 | return *this; | |
668 | } | |
669 | ||
2b5ab1e4 | 670 | template<typename... _Args> |
f11cc050 | 671 | enable_if_t<is_constructible<_Tp, _Args&&...>::value> |
2b5ab1e4 MB |
672 | emplace(_Args&&... __args) |
673 | { | |
2b5ab1e4 MB |
674 | this->_M_reset(); |
675 | this->_M_construct(std::forward<_Args>(__args)...); | |
676 | } | |
677 | ||
678 | template<typename _Up, typename... _Args> | |
f11cc050 | 679 | enable_if_t<is_constructible<_Tp, initializer_list<_Up>&, |
8a57bed1 | 680 | _Args&&...>::value> |
2b5ab1e4 MB |
681 | emplace(initializer_list<_Up> __il, _Args&&... __args) |
682 | { | |
683 | this->_M_reset(); | |
684 | this->_M_construct(__il, std::forward<_Args>(__args)...); | |
685 | } | |
686 | ||
687 | // [X.Y.4.2] Destructor is implicit, implemented in _Optional_base. | |
688 | ||
689 | // [X.Y.4.4] Swap. | |
690 | void | |
691 | swap(optional& __other) | |
692 | noexcept(is_nothrow_move_constructible<_Tp>() | |
71f257f7 | 693 | && __is_nothrow_swappable<_Tp>::value) |
2b5ab1e4 MB |
694 | { |
695 | using std::swap; | |
696 | ||
697 | if (this->_M_is_engaged() && __other._M_is_engaged()) | |
698 | swap(this->_M_get(), __other._M_get()); | |
699 | else if (this->_M_is_engaged()) | |
b1705a63 JW |
700 | { |
701 | __other._M_construct(std::move(this->_M_get())); | |
702 | this->_M_destruct(); | |
703 | } | |
2b5ab1e4 | 704 | else if (__other._M_is_engaged()) |
b1705a63 JW |
705 | { |
706 | this->_M_construct(std::move(__other._M_get())); | |
707 | __other._M_destruct(); | |
708 | } | |
2b5ab1e4 MB |
709 | } |
710 | ||
711 | // [X.Y.4.5] Observers. | |
712 | constexpr const _Tp* | |
713 | operator->() const | |
1637d425 VV |
714 | { |
715 | #ifndef __cpp_lib_addressof_constexpr | |
716 | return __constexpr_addressof(this->_M_get()); | |
717 | #else | |
718 | return std::__addressof(this->_M_get()); | |
719 | #endif | |
720 | } | |
2b5ab1e4 MB |
721 | |
722 | _Tp* | |
723 | operator->() | |
724 | { return std::__addressof(this->_M_get()); } | |
725 | ||
726 | constexpr const _Tp& | |
65545817 | 727 | operator*() const& |
2b5ab1e4 MB |
728 | { return this->_M_get(); } |
729 | ||
65545817 JW |
730 | constexpr _Tp& |
731 | operator*()& | |
2b5ab1e4 MB |
732 | { return this->_M_get(); } |
733 | ||
65545817 JW |
734 | constexpr _Tp&& |
735 | operator*()&& | |
736 | { return std::move(this->_M_get()); } | |
737 | ||
738 | constexpr const _Tp&& | |
739 | operator*() const&& | |
740 | { return std::move(this->_M_get()); } | |
741 | ||
2b5ab1e4 MB |
742 | constexpr explicit operator bool() const noexcept |
743 | { return this->_M_is_engaged(); } | |
744 | ||
745 | constexpr const _Tp& | |
65545817 | 746 | value() const& |
2b5ab1e4 | 747 | { |
b1705a63 JW |
748 | return this->_M_is_engaged() |
749 | ? this->_M_get() | |
750 | : (__throw_bad_optional_access("Attempt to access value of a " | |
751 | "disengaged optional object"), | |
752 | this->_M_get()); | |
2b5ab1e4 MB |
753 | } |
754 | ||
65545817 JW |
755 | constexpr _Tp& |
756 | value()& | |
2b5ab1e4 | 757 | { |
65545817 JW |
758 | return this->_M_is_engaged() |
759 | ? this->_M_get() | |
760 | : (__throw_bad_optional_access("Attempt to access value of a " | |
761 | "disengaged optional object"), | |
762 | this->_M_get()); | |
763 | } | |
2b5ab1e4 | 764 | |
65545817 JW |
765 | constexpr _Tp&& |
766 | value()&& | |
767 | { | |
768 | return this->_M_is_engaged() | |
769 | ? std::move(this->_M_get()) | |
770 | : (__throw_bad_optional_access("Attempt to access value of a " | |
771 | "disengaged optional object"), | |
772 | std::move(this->_M_get())); | |
773 | } | |
774 | ||
775 | constexpr const _Tp&& | |
776 | value() const&& | |
777 | { | |
778 | return this->_M_is_engaged() | |
779 | ? std::move(this->_M_get()) | |
780 | : (__throw_bad_optional_access("Attempt to access value of a " | |
781 | "disengaged optional object"), | |
782 | std::move(this->_M_get())); | |
2b5ab1e4 MB |
783 | } |
784 | ||
785 | template<typename _Up> | |
786 | constexpr _Tp | |
787 | value_or(_Up&& __u) const& | |
788 | { | |
b1705a63 JW |
789 | static_assert(__and_<is_copy_constructible<_Tp>, |
790 | is_convertible<_Up&&, _Tp>>(), | |
791 | "Cannot return value"); | |
2b5ab1e4 | 792 | |
b1705a63 JW |
793 | return this->_M_is_engaged() |
794 | ? this->_M_get() | |
795 | : static_cast<_Tp>(std::forward<_Up>(__u)); | |
2b5ab1e4 MB |
796 | } |
797 | ||
798 | template<typename _Up> | |
799 | _Tp | |
800 | value_or(_Up&& __u) && | |
801 | { | |
b1705a63 JW |
802 | static_assert(__and_<is_move_constructible<_Tp>, |
803 | is_convertible<_Up&&, _Tp>>(), | |
804 | "Cannot return value" ); | |
2b5ab1e4 | 805 | |
b1705a63 JW |
806 | return this->_M_is_engaged() |
807 | ? std::move(this->_M_get()) | |
808 | : static_cast<_Tp>(std::forward<_Up>(__u)); | |
2b5ab1e4 MB |
809 | } |
810 | }; | |
811 | ||
812 | // [X.Y.8] Comparisons between optional values. | |
813 | template<typename _Tp> | |
814 | constexpr bool | |
815 | operator==(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) | |
816 | { | |
817 | return static_cast<bool>(__lhs) == static_cast<bool>(__rhs) | |
b1705a63 | 818 | && (!__lhs || *__lhs == *__rhs); |
2b5ab1e4 MB |
819 | } |
820 | ||
821 | template<typename _Tp> | |
822 | constexpr bool | |
823 | operator!=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) | |
824 | { return !(__lhs == __rhs); } | |
825 | ||
826 | template<typename _Tp> | |
827 | constexpr bool | |
828 | operator<(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) | |
829 | { | |
b1705a63 | 830 | return static_cast<bool>(__rhs) && (!__lhs || *__lhs < *__rhs); |
2b5ab1e4 MB |
831 | } |
832 | ||
833 | template<typename _Tp> | |
834 | constexpr bool | |
835 | operator>(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) | |
836 | { return __rhs < __lhs; } | |
837 | ||
838 | template<typename _Tp> | |
839 | constexpr bool | |
840 | operator<=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) | |
841 | { return !(__rhs < __lhs); } | |
842 | ||
843 | template<typename _Tp> | |
844 | constexpr bool | |
845 | operator>=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs) | |
846 | { return !(__lhs < __rhs); } | |
847 | ||
848 | // [X.Y.9] Comparisons with nullopt. | |
849 | template<typename _Tp> | |
850 | constexpr bool | |
851 | operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept | |
852 | { return !__lhs; } | |
853 | ||
854 | template<typename _Tp> | |
855 | constexpr bool | |
856 | operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept | |
857 | { return !__rhs; } | |
858 | ||
859 | template<typename _Tp> | |
860 | constexpr bool | |
861 | operator!=(const optional<_Tp>& __lhs, nullopt_t) noexcept | |
862 | { return static_cast<bool>(__lhs); } | |
863 | ||
864 | template<typename _Tp> | |
865 | constexpr bool | |
866 | operator!=(nullopt_t, const optional<_Tp>& __rhs) noexcept | |
867 | { return static_cast<bool>(__rhs); } | |
868 | ||
869 | template<typename _Tp> | |
870 | constexpr bool | |
871 | operator<(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept | |
872 | { return false; } | |
873 | ||
874 | template<typename _Tp> | |
875 | constexpr bool | |
876 | operator<(nullopt_t, const optional<_Tp>& __rhs) noexcept | |
877 | { return static_cast<bool>(__rhs); } | |
878 | ||
879 | template<typename _Tp> | |
880 | constexpr bool | |
881 | operator>(const optional<_Tp>& __lhs, nullopt_t) noexcept | |
882 | { return static_cast<bool>(__lhs); } | |
883 | ||
884 | template<typename _Tp> | |
885 | constexpr bool | |
886 | operator>(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept | |
887 | { return false; } | |
888 | ||
889 | template<typename _Tp> | |
890 | constexpr bool | |
891 | operator<=(const optional<_Tp>& __lhs, nullopt_t) noexcept | |
892 | { return !__lhs; } | |
893 | ||
894 | template<typename _Tp> | |
895 | constexpr bool | |
896 | operator<=(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept | |
897 | { return true; } | |
898 | ||
899 | template<typename _Tp> | |
900 | constexpr bool | |
901 | operator>=(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept | |
902 | { return true; } | |
903 | ||
904 | template<typename _Tp> | |
905 | constexpr bool | |
906 | operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept | |
907 | { return !__rhs; } | |
908 | ||
909 | // [X.Y.10] Comparisons with value type. | |
910 | template<typename _Tp> | |
911 | constexpr bool | |
912 | operator==(const optional<_Tp>& __lhs, const _Tp& __rhs) | |
913 | { return __lhs && *__lhs == __rhs; } | |
914 | ||
915 | template<typename _Tp> | |
916 | constexpr bool | |
917 | operator==(const _Tp& __lhs, const optional<_Tp>& __rhs) | |
918 | { return __rhs && __lhs == *__rhs; } | |
919 | ||
920 | template<typename _Tp> | |
921 | constexpr bool | |
922 | operator!=(const optional<_Tp>& __lhs, _Tp const& __rhs) | |
e2ce9436 | 923 | { return !__lhs || !(*__lhs == __rhs); } |
2b5ab1e4 MB |
924 | |
925 | template<typename _Tp> | |
926 | constexpr bool | |
927 | operator!=(const _Tp& __lhs, const optional<_Tp>& __rhs) | |
e2ce9436 | 928 | { return !__rhs || !(__lhs == *__rhs); } |
2b5ab1e4 MB |
929 | |
930 | template<typename _Tp> | |
931 | constexpr bool | |
932 | operator<(const optional<_Tp>& __lhs, const _Tp& __rhs) | |
933 | { return !__lhs || *__lhs < __rhs; } | |
934 | ||
935 | template<typename _Tp> | |
936 | constexpr bool | |
937 | operator<(const _Tp& __lhs, const optional<_Tp>& __rhs) | |
938 | { return __rhs && __lhs < *__rhs; } | |
939 | ||
940 | template<typename _Tp> | |
941 | constexpr bool | |
942 | operator>(const optional<_Tp>& __lhs, const _Tp& __rhs) | |
943 | { return __lhs && __rhs < *__lhs; } | |
944 | ||
945 | template<typename _Tp> | |
946 | constexpr bool | |
947 | operator>(const _Tp& __lhs, const optional<_Tp>& __rhs) | |
948 | { return !__rhs || *__rhs < __lhs; } | |
949 | ||
950 | template<typename _Tp> | |
951 | constexpr bool | |
952 | operator<=(const optional<_Tp>& __lhs, const _Tp& __rhs) | |
953 | { return !__lhs || !(__rhs < *__lhs); } | |
954 | ||
955 | template<typename _Tp> | |
956 | constexpr bool | |
957 | operator<=(const _Tp& __lhs, const optional<_Tp>& __rhs) | |
958 | { return __rhs && !(*__rhs < __lhs); } | |
959 | ||
960 | template<typename _Tp> | |
961 | constexpr bool | |
962 | operator>=(const optional<_Tp>& __lhs, const _Tp& __rhs) | |
963 | { return __lhs && !(*__lhs < __rhs); } | |
964 | ||
965 | template<typename _Tp> | |
966 | constexpr bool | |
967 | operator>=(const _Tp& __lhs, const optional<_Tp>& __rhs) | |
968 | { return !__rhs || !(__lhs < *__rhs); } | |
969 | ||
970 | // [X.Y.11] | |
971 | template<typename _Tp> | |
b1705a63 | 972 | inline void |
2b5ab1e4 MB |
973 | swap(optional<_Tp>& __lhs, optional<_Tp>& __rhs) |
974 | noexcept(noexcept(__lhs.swap(__rhs))) | |
975 | { __lhs.swap(__rhs); } | |
976 | ||
977 | template<typename _Tp> | |
8a57bed1 | 978 | constexpr optional<decay_t<_Tp>> |
2b5ab1e4 | 979 | make_optional(_Tp&& __t) |
8a57bed1 | 980 | { return optional<decay_t<_Tp>> { std::forward<_Tp>(__t) }; } |
2b5ab1e4 MB |
981 | |
982 | // @} group optional | |
7ce56fc8 | 983 | } // namespace fundamentals_v1 |
4a15d842 | 984 | } // namespace experimental |
2b5ab1e4 MB |
985 | |
986 | // [X.Y.12] | |
987 | template<typename _Tp> | |
988 | struct hash<experimental::optional<_Tp>> | |
989 | { | |
990 | using result_type = size_t; | |
991 | using argument_type = experimental::optional<_Tp>; | |
992 | ||
993 | size_t | |
994 | operator()(const experimental::optional<_Tp>& __t) const | |
995 | noexcept(noexcept(hash<_Tp> {}(*__t))) | |
996 | { | |
997 | // We pick an arbitrary hash for disengaged optionals which hopefully | |
998 | // usual values of _Tp won't typically hash to. | |
999 | constexpr size_t __magic_disengaged_hash = static_cast<size_t>(-3333); | |
1000 | return __t ? hash<_Tp> {}(*__t) : __magic_disengaged_hash; | |
1001 | } | |
1002 | }; | |
4a15d842 FD |
1003 | |
1004 | _GLIBCXX_END_NAMESPACE_VERSION | |
1005 | } // namespace std | |
2b5ab1e4 MB |
1006 | |
1007 | #endif // C++14 | |
1008 | ||
1009 | #endif // _GLIBCXX_EXPERIMENTAL_OPTIONAL |