1 | // <any> -*- C++ -*- |
2 | |
3 | // Copyright (C) 2014-2021 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 include/any |
26 | * This is a Standard C++ Library header. |
27 | */ |
28 | |
29 | #ifndef _GLIBCXX_ANY |
30 | #define _GLIBCXX_ANY 1 |
31 | |
32 | #pragma GCC system_header |
33 | |
34 | #if __cplusplus >= 201703L |
35 | |
36 | #include <typeinfo> |
37 | #include <new> |
38 | #include <utility> |
39 | #include <type_traits> |
40 | |
41 | namespace std _GLIBCXX_VISIBILITY(default) |
42 | { |
43 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
44 | |
45 | /** |
46 | * @addtogroup utilities |
47 | * @{ |
48 | */ |
49 | |
50 | /** |
51 | * @brief Exception class thrown by a failed @c any_cast |
52 | * @ingroup exceptions |
53 | */ |
54 | class bad_any_cast : public bad_cast |
55 | { |
56 | public: |
57 | virtual const char* what() const noexcept { return "bad any_cast" ; } |
58 | }; |
59 | |
60 | [[gnu::noreturn]] inline void __throw_bad_any_cast() |
61 | { |
62 | #if __cpp_exceptions |
63 | throw bad_any_cast{}; |
64 | #else |
65 | __builtin_abort(); |
66 | #endif |
67 | } |
68 | |
69 | #define __cpp_lib_any 201606L |
70 | |
71 | /** |
72 | * @brief A type-safe container of any type. |
73 | * |
74 | * An @c any object's state is either empty or it stores a contained object |
75 | * of CopyConstructible type. |
76 | */ |
77 | class any |
78 | { |
79 | // Holds either pointer to a heap object or the contained object itself. |
80 | union _Storage |
81 | { |
82 | constexpr _Storage() : _M_ptr{nullptr} {} |
83 | |
84 | // Prevent trivial copies of this type, buffer might hold a non-POD. |
85 | _Storage(const _Storage&) = delete; |
86 | _Storage& operator=(const _Storage&) = delete; |
87 | |
88 | void* _M_ptr; |
89 | aligned_storage<sizeof(_M_ptr), alignof(void*)>::type _M_buffer; |
90 | }; |
91 | |
92 | template<typename _Tp, typename _Safe = is_nothrow_move_constructible<_Tp>, |
93 | bool _Fits = (sizeof(_Tp) <= sizeof(_Storage)) |
94 | && (alignof(_Tp) <= alignof(_Storage))> |
95 | using _Internal = std::integral_constant<bool, _Safe::value && _Fits>; |
96 | |
97 | template<typename _Tp> |
98 | struct _Manager_internal; // uses small-object optimization |
99 | |
100 | template<typename _Tp> |
101 | struct _Manager_external; // creates contained object on the heap |
102 | |
103 | template<typename _Tp> |
104 | using _Manager = conditional_t<_Internal<_Tp>::value, |
105 | _Manager_internal<_Tp>, |
106 | _Manager_external<_Tp>>; |
107 | |
108 | template<typename _Tp, typename _VTp = decay_t<_Tp>> |
109 | using _Decay_if_not_any = enable_if_t<!is_same_v<_VTp, any>, _VTp>; |
110 | |
111 | /// Emplace with an object created from @p __args as the contained object. |
112 | template <typename _Tp, typename... _Args, |
113 | typename _Mgr = _Manager<_Tp>> |
114 | void __do_emplace(_Args&&... __args) |
115 | { |
116 | reset(); |
117 | _Mgr::_S_create(_M_storage, std::forward<_Args>(__args)...); |
118 | _M_manager = &_Mgr::_S_manage; |
119 | } |
120 | |
121 | /// Emplace with an object created from @p __il and @p __args as |
122 | /// the contained object. |
123 | template <typename _Tp, typename _Up, typename... _Args, |
124 | typename _Mgr = _Manager<_Tp>> |
125 | void __do_emplace(initializer_list<_Up> __il, _Args&&... __args) |
126 | { |
127 | reset(); |
128 | _Mgr::_S_create(_M_storage, __il, std::forward<_Args>(__args)...); |
129 | _M_manager = &_Mgr::_S_manage; |
130 | } |
131 | |
132 | template <typename _Res, typename _Tp, typename... _Args> |
133 | using __any_constructible |
134 | = enable_if<__and_<is_copy_constructible<_Tp>, |
135 | is_constructible<_Tp, _Args...>>::value, |
136 | _Res>; |
137 | |
138 | template <typename _Tp, typename... _Args> |
139 | using __any_constructible_t |
140 | = typename __any_constructible<bool, _Tp, _Args...>::type; |
141 | |
142 | template<typename _VTp, typename... _Args> |
143 | using __emplace_t |
144 | = typename __any_constructible<_VTp&, _VTp, _Args...>::type; |
145 | |
146 | public: |
147 | // construct/destruct |
148 | |
149 | /// Default constructor, creates an empty object. |
150 | constexpr any() noexcept : _M_manager(nullptr) { } |
151 | |
152 | /// Copy constructor, copies the state of @p __other |
153 | any(const any& __other) |
154 | { |
155 | if (!__other.has_value()) |
156 | _M_manager = nullptr; |
157 | else |
158 | { |
159 | _Arg __arg; |
160 | __arg._M_any = this; |
161 | __other._M_manager(_Op_clone, &__other, &__arg); |
162 | } |
163 | } |
164 | |
165 | /** |
166 | * @brief Move constructor, transfer the state from @p __other |
167 | * |
168 | * @post @c !__other.has_value() (this postcondition is a GNU extension) |
169 | */ |
170 | any(any&& __other) noexcept |
171 | { |
172 | if (!__other.has_value()) |
173 | _M_manager = nullptr; |
174 | else |
175 | { |
176 | _Arg __arg; |
177 | __arg._M_any = this; |
178 | __other._M_manager(_Op_xfer, &__other, &__arg); |
179 | } |
180 | } |
181 | |
182 | /// Construct with a copy of @p __value as the contained object. |
183 | template <typename _Tp, typename _VTp = _Decay_if_not_any<_Tp>, |
184 | typename _Mgr = _Manager<_VTp>, |
185 | enable_if_t<is_copy_constructible<_VTp>::value |
186 | && !__is_in_place_type<_VTp>::value, bool> = true> |
187 | any(_Tp&& __value) |
188 | : _M_manager(&_Mgr::_S_manage) |
189 | { |
190 | _Mgr::_S_create(_M_storage, std::forward<_Tp>(__value)); |
191 | } |
192 | |
193 | /// Construct with an object created from @p __args as the contained object. |
194 | template <typename _Tp, typename... _Args, typename _VTp = decay_t<_Tp>, |
195 | typename _Mgr = _Manager<_VTp>, |
196 | __any_constructible_t<_VTp, _Args&&...> = false> |
197 | explicit |
198 | any(in_place_type_t<_Tp>, _Args&&... __args) |
199 | : _M_manager(&_Mgr::_S_manage) |
200 | { |
201 | _Mgr::_S_create(_M_storage, std::forward<_Args>(__args)...); |
202 | } |
203 | |
204 | /// Construct with an object created from @p __il and @p __args as |
205 | /// the contained object. |
206 | template <typename _Tp, typename _Up, typename... _Args, |
207 | typename _VTp = decay_t<_Tp>, typename _Mgr = _Manager<_VTp>, |
208 | __any_constructible_t<_VTp, initializer_list<_Up>&, |
209 | _Args&&...> = false> |
210 | explicit |
211 | any(in_place_type_t<_Tp>, initializer_list<_Up> __il, _Args&&... __args) |
212 | : _M_manager(&_Mgr::_S_manage) |
213 | { |
214 | _Mgr::_S_create(_M_storage, __il, std::forward<_Args>(__args)...); |
215 | } |
216 | |
217 | /// Destructor, calls @c reset() |
218 | ~any() { reset(); } |
219 | |
220 | // assignments |
221 | |
222 | /// Copy the state of another object. |
223 | any& |
224 | operator=(const any& __rhs) |
225 | { |
226 | *this = any(__rhs); |
227 | return *this; |
228 | } |
229 | |
230 | /** |
231 | * @brief Move assignment operator |
232 | * |
233 | * @post @c !__rhs.has_value() (not guaranteed for other implementations) |
234 | */ |
235 | any& |
236 | operator=(any&& __rhs) noexcept |
237 | { |
238 | if (!__rhs.has_value()) |
239 | reset(); |
240 | else if (this != &__rhs) |
241 | { |
242 | reset(); |
243 | _Arg __arg; |
244 | __arg._M_any = this; |
245 | __rhs._M_manager(_Op_xfer, &__rhs, &__arg); |
246 | } |
247 | return *this; |
248 | } |
249 | |
250 | /// Store a copy of @p __rhs as the contained object. |
251 | template<typename _Tp> |
252 | enable_if_t<is_copy_constructible<_Decay_if_not_any<_Tp>>::value, any&> |
253 | operator=(_Tp&& __rhs) |
254 | { |
255 | *this = any(std::forward<_Tp>(__rhs)); |
256 | return *this; |
257 | } |
258 | |
259 | /// Emplace with an object created from @p __args as the contained object. |
260 | template <typename _Tp, typename... _Args> |
261 | __emplace_t<decay_t<_Tp>, _Args...> |
262 | emplace(_Args&&... __args) |
263 | { |
264 | using _VTp = decay_t<_Tp>; |
265 | __do_emplace<_VTp>(std::forward<_Args>(__args)...); |
266 | any::_Arg __arg; |
267 | this->_M_manager(any::_Op_access, this, &__arg); |
268 | return *static_cast<_VTp*>(__arg._M_obj); |
269 | } |
270 | |
271 | /// Emplace with an object created from @p __il and @p __args as |
272 | /// the contained object. |
273 | template <typename _Tp, typename _Up, typename... _Args> |
274 | __emplace_t<decay_t<_Tp>, initializer_list<_Up>&, _Args&&...> |
275 | emplace(initializer_list<_Up> __il, _Args&&... __args) |
276 | { |
277 | using _VTp = decay_t<_Tp>; |
278 | __do_emplace<_VTp, _Up>(__il, std::forward<_Args>(__args)...); |
279 | any::_Arg __arg; |
280 | this->_M_manager(any::_Op_access, this, &__arg); |
281 | return *static_cast<_VTp*>(__arg._M_obj); |
282 | } |
283 | |
284 | // modifiers |
285 | |
286 | /// If not empty, destroy the contained object. |
287 | void reset() noexcept |
288 | { |
289 | if (has_value()) |
290 | { |
291 | _M_manager(_Op_destroy, this, nullptr); |
292 | _M_manager = nullptr; |
293 | } |
294 | } |
295 | |
296 | /// Exchange state with another object. |
297 | void swap(any& __rhs) noexcept |
298 | { |
299 | if (!has_value() && !__rhs.has_value()) |
300 | return; |
301 | |
302 | if (has_value() && __rhs.has_value()) |
303 | { |
304 | if (this == &__rhs) |
305 | return; |
306 | |
307 | any __tmp; |
308 | _Arg __arg; |
309 | __arg._M_any = &__tmp; |
310 | __rhs._M_manager(_Op_xfer, &__rhs, &__arg); |
311 | __arg._M_any = &__rhs; |
312 | _M_manager(_Op_xfer, this, &__arg); |
313 | __arg._M_any = this; |
314 | __tmp._M_manager(_Op_xfer, &__tmp, &__arg); |
315 | } |
316 | else |
317 | { |
318 | any* __empty = !has_value() ? this : &__rhs; |
319 | any* __full = !has_value() ? &__rhs : this; |
320 | _Arg __arg; |
321 | __arg._M_any = __empty; |
322 | __full->_M_manager(_Op_xfer, __full, &__arg); |
323 | } |
324 | } |
325 | |
326 | // observers |
327 | |
328 | /// Reports whether there is a contained object or not. |
329 | bool has_value() const noexcept { return _M_manager != nullptr; } |
330 | |
331 | #if __cpp_rtti |
332 | /// The @c typeid of the contained object, or @c typeid(void) if empty. |
333 | const type_info& type() const noexcept |
334 | { |
335 | if (!has_value()) |
336 | return typeid(void); |
337 | _Arg __arg; |
338 | _M_manager(_Op_get_type_info, this, &__arg); |
339 | return *__arg._M_typeinfo; |
340 | } |
341 | #endif |
342 | |
343 | template<typename _Tp> |
344 | static constexpr bool __is_valid_cast() |
345 | { return __or_<is_reference<_Tp>, is_copy_constructible<_Tp>>::value; } |
346 | |
347 | private: |
348 | enum _Op { |
349 | _Op_access, _Op_get_type_info, _Op_clone, _Op_destroy, _Op_xfer |
350 | }; |
351 | |
352 | union _Arg |
353 | { |
354 | void* _M_obj; |
355 | const std::type_info* _M_typeinfo; |
356 | any* _M_any; |
357 | }; |
358 | |
359 | void (*_M_manager)(_Op, const any*, _Arg*); |
360 | _Storage _M_storage; |
361 | |
362 | template<typename _Tp> |
363 | friend void* __any_caster(const any* __any); |
364 | |
365 | // Manage in-place contained object. |
366 | template<typename _Tp> |
367 | struct _Manager_internal |
368 | { |
369 | static void |
370 | _S_manage(_Op __which, const any* __anyp, _Arg* __arg); |
371 | |
372 | template<typename _Up> |
373 | static void |
374 | _S_create(_Storage& __storage, _Up&& __value) |
375 | { |
376 | void* __addr = &__storage._M_buffer; |
377 | ::new (__addr) _Tp(std::forward<_Up>(__value)); |
378 | } |
379 | |
380 | template<typename... _Args> |
381 | static void |
382 | _S_create(_Storage& __storage, _Args&&... __args) |
383 | { |
384 | void* __addr = &__storage._M_buffer; |
385 | ::new (__addr) _Tp(std::forward<_Args>(__args)...); |
386 | } |
387 | }; |
388 | |
389 | // Manage external contained object. |
390 | template<typename _Tp> |
391 | struct _Manager_external |
392 | { |
393 | static void |
394 | _S_manage(_Op __which, const any* __anyp, _Arg* __arg); |
395 | |
396 | template<typename _Up> |
397 | static void |
398 | _S_create(_Storage& __storage, _Up&& __value) |
399 | { |
400 | __storage._M_ptr = new _Tp(std::forward<_Up>(__value)); |
401 | } |
402 | template<typename... _Args> |
403 | static void |
404 | _S_create(_Storage& __storage, _Args&&... __args) |
405 | { |
406 | __storage._M_ptr = new _Tp(std::forward<_Args>(__args)...); |
407 | } |
408 | }; |
409 | }; |
410 | |
411 | /// Exchange the states of two @c any objects. |
412 | inline void swap(any& __x, any& __y) noexcept { __x.swap(__y); } |
413 | |
414 | /// Create an any holding a @c _Tp constructed from @c __args. |
415 | template <typename _Tp, typename... _Args> |
416 | any make_any(_Args&&... __args) |
417 | { |
418 | return any(in_place_type<_Tp>, std::forward<_Args>(__args)...); |
419 | } |
420 | |
421 | /// Create an any holding a @c _Tp constructed from @c __il and @c __args. |
422 | template <typename _Tp, typename _Up, typename... _Args> |
423 | any make_any(initializer_list<_Up> __il, _Args&&... __args) |
424 | { |
425 | return any(in_place_type<_Tp>, __il, std::forward<_Args>(__args)...); |
426 | } |
427 | |
428 | /** |
429 | * @brief Access the contained object. |
430 | * |
431 | * @tparam _ValueType A const-reference or CopyConstructible type. |
432 | * @param __any The object to access. |
433 | * @return The contained object. |
434 | * @throw bad_any_cast If <code> |
435 | * __any.type() != typeid(remove_reference_t<_ValueType>) |
436 | * </code> |
437 | */ |
438 | template<typename _ValueType> |
439 | inline _ValueType any_cast(const any& __any) |
440 | { |
441 | using _Up = __remove_cvref_t<_ValueType>; |
442 | static_assert(any::__is_valid_cast<_ValueType>(), |
443 | "Template argument must be a reference or CopyConstructible type" ); |
444 | static_assert(is_constructible_v<_ValueType, const _Up&>, |
445 | "Template argument must be constructible from a const value." ); |
446 | auto __p = any_cast<_Up>(&__any); |
447 | if (__p) |
448 | return static_cast<_ValueType>(*__p); |
449 | __throw_bad_any_cast(); |
450 | } |
451 | |
452 | /** |
453 | * @brief Access the contained object. |
454 | * |
455 | * @tparam _ValueType A reference or CopyConstructible type. |
456 | * @param __any The object to access. |
457 | * @return The contained object. |
458 | * @throw bad_any_cast If <code> |
459 | * __any.type() != typeid(remove_reference_t<_ValueType>) |
460 | * </code> |
461 | * |
462 | * @{ |
463 | */ |
464 | template<typename _ValueType> |
465 | inline _ValueType any_cast(any& __any) |
466 | { |
467 | using _Up = __remove_cvref_t<_ValueType>; |
468 | static_assert(any::__is_valid_cast<_ValueType>(), |
469 | "Template argument must be a reference or CopyConstructible type" ); |
470 | static_assert(is_constructible_v<_ValueType, _Up&>, |
471 | "Template argument must be constructible from an lvalue." ); |
472 | auto __p = any_cast<_Up>(&__any); |
473 | if (__p) |
474 | return static_cast<_ValueType>(*__p); |
475 | __throw_bad_any_cast(); |
476 | } |
477 | |
478 | template<typename _ValueType> |
479 | inline _ValueType any_cast(any&& __any) |
480 | { |
481 | using _Up = __remove_cvref_t<_ValueType>; |
482 | static_assert(any::__is_valid_cast<_ValueType>(), |
483 | "Template argument must be a reference or CopyConstructible type" ); |
484 | static_assert(is_constructible_v<_ValueType, _Up>, |
485 | "Template argument must be constructible from an rvalue." ); |
486 | auto __p = any_cast<_Up>(&__any); |
487 | if (__p) |
488 | return static_cast<_ValueType>(std::move(*__p)); |
489 | __throw_bad_any_cast(); |
490 | } |
491 | /// @} |
492 | |
493 | /// @cond undocumented |
494 | template<typename _Tp> |
495 | void* __any_caster(const any* __any) |
496 | { |
497 | // any_cast<T> returns non-null if __any->type() == typeid(T) and |
498 | // typeid(T) ignores cv-qualifiers so remove them: |
499 | using _Up = remove_cv_t<_Tp>; |
500 | // The contained value has a decayed type, so if decay_t<U> is not U, |
501 | // then it's not possible to have a contained value of type U: |
502 | if constexpr (!is_same_v<decay_t<_Up>, _Up>) |
503 | return nullptr; |
504 | // Only copy constructible types can be used for contained values: |
505 | else if constexpr (!is_copy_constructible_v<_Up>) |
506 | return nullptr; |
507 | // First try comparing function addresses, which works without RTTI |
508 | else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage |
509 | #if __cpp_rtti |
510 | || __any->type() == typeid(_Tp) |
511 | #endif |
512 | ) |
513 | { |
514 | any::_Arg __arg; |
515 | __any->_M_manager(any::_Op_access, __any, &__arg); |
516 | return __arg._M_obj; |
517 | } |
518 | return nullptr; |
519 | } |
520 | /// @endcond |
521 | |
522 | /** |
523 | * @brief Access the contained object. |
524 | * |
525 | * @tparam _ValueType The type of the contained object. |
526 | * @param __any A pointer to the object to access. |
527 | * @return The address of the contained object if <code> |
528 | * __any != nullptr && __any.type() == typeid(_ValueType) |
529 | * </code>, otherwise a null pointer. |
530 | * |
531 | * @{ |
532 | */ |
533 | template<typename _ValueType> |
534 | inline const _ValueType* any_cast(const any* __any) noexcept |
535 | { |
536 | if constexpr (is_object_v<_ValueType>) |
537 | if (__any) |
538 | return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); |
539 | return nullptr; |
540 | } |
541 | |
542 | template<typename _ValueType> |
543 | inline _ValueType* any_cast(any* __any) noexcept |
544 | { |
545 | if constexpr (is_object_v<_ValueType>) |
546 | if (__any) |
547 | return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); |
548 | return nullptr; |
549 | } |
550 | /// @} |
551 | |
552 | template<typename _Tp> |
553 | void |
554 | any::_Manager_internal<_Tp>:: |
555 | _S_manage(_Op __which, const any* __any, _Arg* __arg) |
556 | { |
557 | // The contained object is in _M_storage._M_buffer |
558 | auto __ptr = reinterpret_cast<const _Tp*>(&__any->_M_storage._M_buffer); |
559 | switch (__which) |
560 | { |
561 | case _Op_access: |
562 | __arg->_M_obj = const_cast<_Tp*>(__ptr); |
563 | break; |
564 | case _Op_get_type_info: |
565 | #if __cpp_rtti |
566 | __arg->_M_typeinfo = &typeid(_Tp); |
567 | #endif |
568 | break; |
569 | case _Op_clone: |
570 | ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); |
571 | __arg->_M_any->_M_manager = __any->_M_manager; |
572 | break; |
573 | case _Op_destroy: |
574 | __ptr->~_Tp(); |
575 | break; |
576 | case _Op_xfer: |
577 | ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp |
578 | (std::move(*const_cast<_Tp*>(__ptr))); |
579 | __ptr->~_Tp(); |
580 | __arg->_M_any->_M_manager = __any->_M_manager; |
581 | const_cast<any*>(__any)->_M_manager = nullptr; |
582 | break; |
583 | } |
584 | } |
585 | |
586 | template<typename _Tp> |
587 | void |
588 | any::_Manager_external<_Tp>:: |
589 | _S_manage(_Op __which, const any* __any, _Arg* __arg) |
590 | { |
591 | // The contained object is *_M_storage._M_ptr |
592 | auto __ptr = static_cast<const _Tp*>(__any->_M_storage._M_ptr); |
593 | switch (__which) |
594 | { |
595 | case _Op_access: |
596 | __arg->_M_obj = const_cast<_Tp*>(__ptr); |
597 | break; |
598 | case _Op_get_type_info: |
599 | #if __cpp_rtti |
600 | __arg->_M_typeinfo = &typeid(_Tp); |
601 | #endif |
602 | break; |
603 | case _Op_clone: |
604 | __arg->_M_any->_M_storage._M_ptr = new _Tp(*__ptr); |
605 | __arg->_M_any->_M_manager = __any->_M_manager; |
606 | break; |
607 | case _Op_destroy: |
608 | delete __ptr; |
609 | break; |
610 | case _Op_xfer: |
611 | __arg->_M_any->_M_storage._M_ptr = __any->_M_storage._M_ptr; |
612 | __arg->_M_any->_M_manager = __any->_M_manager; |
613 | const_cast<any*>(__any)->_M_manager = nullptr; |
614 | break; |
615 | } |
616 | } |
617 | |
618 | /// @} |
619 | |
620 | namespace __detail::__variant |
621 | { |
622 | template<typename> struct _Never_valueless_alt; // see <variant> |
623 | |
624 | // Provide the strong exception-safety guarantee when emplacing an |
625 | // any into a variant. |
626 | template<> |
627 | struct _Never_valueless_alt<std::any> |
628 | : std::true_type |
629 | { }; |
630 | } // namespace __detail::__variant |
631 | |
632 | _GLIBCXX_END_NAMESPACE_VERSION |
633 | } // namespace std |
634 | |
635 | #endif // C++17 |
636 | #endif // _GLIBCXX_ANY |
637 | |