libstdc++
experimental/any
Go to the documentation of this file.
1// <experimental/any> -*- C++ -*-
2
3// Copyright (C) 2014-2025 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/any
26 * This is a TS C++ Library header.
27 * @ingroup libfund-ts
28 */
29
30#ifndef _GLIBCXX_EXPERIMENTAL_ANY
31#define _GLIBCXX_EXPERIMENTAL_ANY 1
32
33#ifdef _GLIBCXX_SYSHDR
34#pragma GCC system_header
35#endif
36
37#include <bits/requires_hosted.h> // experimental is currently omitted
38
39#if __cplusplus >= 201402L
40
41#include <typeinfo>
42#include <new>
43#include <type_traits>
44#include <bits/move.h>
46
47namespace std _GLIBCXX_VISIBILITY(default)
48{
49_GLIBCXX_BEGIN_NAMESPACE_VERSION
50
51namespace experimental
52{
53inline namespace fundamentals_v1
54{
55 /**
56 * @defgroup any Type-safe container of any type
57 * @ingroup libfund-ts
58 *
59 * A type-safe container for single values of value types, as
60 * described in n3804 "Any Library Proposal (Revision 3)".
61 *
62 * @{
63 */
64
65#define __cpp_lib_experimental_any 201411
66
67 /**
68 * @brief Exception class thrown by a failed @c any_cast
69 * @ingroup exceptions
70 */
71 class bad_any_cast : public bad_cast
72 {
73 public:
74 virtual const char* what() const noexcept { return "bad any_cast"; }
75 };
76
77 /// @cond undocumented
78 [[gnu::noreturn]] inline void __throw_bad_any_cast()
79 {
80#if __cpp_exceptions
81 throw bad_any_cast{};
82#else
83 __builtin_abort();
84#endif
85 }
86 /// @endcond
87
88 /**
89 * @brief A type-safe container of any type.
90 *
91 * An @c any object's state is either empty or it stores a contained object
92 * of CopyConstructible type.
93 */
94 class any
95 {
96 // Holds either pointer to a heap object or the contained object itself.
97 union _Storage
98 {
99 // This constructor intentionally doesn't initialize anything.
100 _Storage() = default;
101
102 // Prevent trivial copies of this type, buffer might hold a non-POD.
103 _Storage(const _Storage&) = delete;
104 _Storage& operator=(const _Storage&) = delete;
105
106 void* _M_ptr;
107 unsigned char _M_buffer[sizeof(_M_ptr)];
108 };
109
110 template<typename _Tp, typename _Safe = is_nothrow_move_constructible<_Tp>,
111 bool _Fits = (sizeof(_Tp) <= sizeof(_Storage))
112 && (alignof(_Tp) <= alignof(_Storage))>
113 using _Internal = std::integral_constant<bool, _Safe::value && _Fits>;
114
115 template<typename _Tp>
116 struct _Manager_internal; // uses small-object optimization
117
118 template<typename _Tp>
119 struct _Manager_external; // creates contained object on the heap
120
121 template<typename _Tp>
122 using _Manager = __conditional_t<_Internal<_Tp>::value,
123 _Manager_internal<_Tp>,
124 _Manager_external<_Tp>>;
125
126 template<typename _Tp, typename _Decayed = decay_t<_Tp>>
127 using _Decay = enable_if_t<!is_same<_Decayed, any>::value, _Decayed>;
128
129 public:
130 // construct/destruct
131
132 /// Default constructor, creates an empty object.
133 any() noexcept : _M_manager(nullptr) { }
134
135 /// Copy constructor, copies the state of @p __other
136 any(const any& __other)
137 {
138 if (__other.empty())
139 _M_manager = nullptr;
140 else
141 {
142 _Arg __arg;
143 __arg._M_any = this;
144 __other._M_manager(_Op_clone, &__other, &__arg);
145 }
146 }
147
148 /**
149 * @brief Move constructor, transfer the state from @p __other
150 *
151 * @post @c __other.empty() (this postcondition is a GNU extension)
152 */
153 any(any&& __other) noexcept
154 {
155 if (__other.empty())
156 _M_manager = nullptr;
157 else
158 {
159 _Arg __arg;
160 __arg._M_any = this;
161 __other._M_manager(_Op_xfer, &__other, &__arg);
162 }
163 }
164
165 /// Construct with a copy of @p __value as the contained object.
166 template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
167 typename _Mgr = _Manager<_Tp>,
168 typename enable_if<is_constructible<_Tp, _ValueType&&>::value,
169 bool>::type = true>
170 any(_ValueType&& __value)
171 : _M_manager(&_Mgr::_S_manage)
172 {
173 _Mgr::_S_create(_M_storage, std::forward<_ValueType>(__value));
175 "The contained object must be CopyConstructible");
176 }
177
178 /// Construct with a copy of @p __value as the contained object.
179 template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
180 typename _Mgr = _Manager<_Tp>,
181 typename enable_if<!is_constructible<_Tp, _ValueType&&>::value,
182 bool>::type = false>
183 any(_ValueType&& __value)
184 : _M_manager(&_Mgr::_S_manage)
185 {
186 _Mgr::_S_create(_M_storage, __value);
188 "The contained object must be CopyConstructible");
189 }
190
191 /// Destructor, calls @c clear()
192 ~any() { clear(); }
193
194 // assignments
195
196 /// Copy the state of another object.
197 any& operator=(const any& __rhs)
198 {
199 *this = any(__rhs);
200 return *this;
201 }
202
203 /**
204 * @brief Move assignment operator
205 *
206 * @post @c __rhs.empty() (not guaranteed for other implementations)
207 */
208 any& operator=(any&& __rhs) noexcept
209 {
210 if (__rhs.empty())
211 clear();
212 else if (this != &__rhs)
213 {
214 clear();
215 _Arg __arg;
216 __arg._M_any = this;
217 __rhs._M_manager(_Op_xfer, &__rhs, &__arg);
218 }
219 return *this;
220 }
221
222 /// Store a copy of @p __rhs as the contained object.
223 template<typename _ValueType>
225 operator=(_ValueType&& __rhs)
226 {
227 *this = any(std::forward<_ValueType>(__rhs));
228 return *this;
229 }
230
231 // modifiers
232
233 /// If not empty, destroy the contained object.
234 void clear() noexcept
235 {
236 if (!empty())
237 {
238 _M_manager(_Op_destroy, this, nullptr);
239 _M_manager = nullptr;
240 }
241 }
242
243 /// Exchange state with another object.
244 void swap(any& __rhs) noexcept
245 {
246 if (empty() && __rhs.empty())
247 return;
248
249 if (!empty() && !__rhs.empty())
250 {
251 if (this == &__rhs)
252 return;
253
254 any __tmp;
255 _Arg __arg;
256 __arg._M_any = &__tmp;
257 __rhs._M_manager(_Op_xfer, &__rhs, &__arg);
258 __arg._M_any = &__rhs;
259 _M_manager(_Op_xfer, this, &__arg);
260 __arg._M_any = this;
261 __tmp._M_manager(_Op_xfer, &__tmp, &__arg);
262 }
263 else
264 {
265 any* __empty = empty() ? this : &__rhs;
266 any* __full = empty() ? &__rhs : this;
267 _Arg __arg;
268 __arg._M_any = __empty;
269 __full->_M_manager(_Op_xfer, __full, &__arg);
270 }
271 }
272
273 // observers
274
275 /// Reports whether there is a contained object or not.
276 _GLIBCXX_NODISCARD bool empty() const noexcept { return _M_manager == nullptr; }
277
278#if __cpp_rtti
279 /// The @c typeid of the contained object, or @c typeid(void) if empty.
280 const type_info& type() const noexcept
281 {
282 if (empty())
283 return typeid(void);
284 _Arg __arg;
285 _M_manager(_Op_get_type_info, this, &__arg);
286 return *__arg._M_typeinfo;
287 }
288#endif
289
290 template<typename _Tp>
291 static constexpr bool __is_valid_cast()
292 { return __or_<is_reference<_Tp>, is_copy_constructible<_Tp>>::value; }
293
294 private:
295 enum _Op {
296 _Op_access, _Op_get_type_info, _Op_clone, _Op_destroy, _Op_xfer
297 };
298
299 union _Arg
300 {
301 void* _M_obj;
302 const std::type_info* _M_typeinfo;
303 any* _M_any;
304 };
305
306 void (*_M_manager)(_Op, const any*, _Arg*);
307 _Storage _M_storage;
308
309 template<typename _Tp>
310 friend enable_if_t<is_object<_Tp>::value, void*>
311 __any_caster(const any* __any);
312
313 // Manage in-place contained object.
314 template<typename _Tp>
315 struct _Manager_internal
316 {
317 static void
318 _S_manage(_Op __which, const any* __anyp, _Arg* __arg);
319
320 template<typename _Up>
321 static void
322 _S_create(_Storage& __storage, _Up&& __value)
323 {
324 void* __addr = &__storage._M_buffer;
325 ::new (__addr) _Tp(std::forward<_Up>(__value));
326 }
327 };
328
329 // Manage external contained object.
330 template<typename _Tp>
331 struct _Manager_external
332 {
333 static void
334 _S_manage(_Op __which, const any* __anyp, _Arg* __arg);
335
336 template<typename _Up>
337 static void
338 _S_create(_Storage& __storage, _Up&& __value)
339 {
340 __storage._M_ptr = new _Tp(std::forward<_Up>(__value));
341 }
342 };
343 };
344
345 /// Exchange the states of two @c any objects.
346 inline void swap(any& __x, any& __y) noexcept { __x.swap(__y); }
347
348 /**
349 * @brief Access the contained object.
350 *
351 * @tparam _ValueType A const-reference or CopyConstructible type.
352 * @param __any The object to access.
353 * @return The contained object.
354 * @throw bad_any_cast If <code>
355 * __any.type() != typeid(remove_reference_t<_ValueType>)
356 * </code>
357 */
358 template<typename _ValueType>
359 inline _ValueType any_cast(const any& __any)
360 {
361 static_assert(any::__is_valid_cast<_ValueType>(),
362 "Template argument must be a reference or CopyConstructible type");
363 auto __p = any_cast<add_const_t<remove_reference_t<_ValueType>>>(&__any);
364 if (__p)
365 return *__p;
366 __throw_bad_any_cast();
367 }
368
369 /**
370 * @brief Access the contained object.
371 *
372 * @tparam _ValueType A reference or CopyConstructible type.
373 * @param __any The object to access.
374 * @return The contained object.
375 * @throw bad_any_cast If <code>
376 * __any.type() != typeid(remove_reference_t<_ValueType>)
377 * </code>
378 *
379 * @{
380 */
381 template<typename _ValueType>
382 inline _ValueType any_cast(any& __any)
383 {
384 static_assert(any::__is_valid_cast<_ValueType>(),
385 "Template argument must be a reference or CopyConstructible type");
386 auto __p = any_cast<remove_reference_t<_ValueType>>(&__any);
387 if (__p)
388 return *__p;
389 __throw_bad_any_cast();
390 }
391
392 template<typename _ValueType,
395 bool>::type = true>
396 inline _ValueType any_cast(any&& __any)
397 {
398 static_assert(any::__is_valid_cast<_ValueType>(),
399 "Template argument must be a reference or CopyConstructible type");
400 auto __p = any_cast<remove_reference_t<_ValueType>>(&__any);
401 if (__p)
402 return *__p;
403 __throw_bad_any_cast();
404 }
405
406 template<typename _ValueType,
409 bool>::type = false>
410 inline _ValueType any_cast(any&& __any)
411 {
412 static_assert(any::__is_valid_cast<_ValueType>(),
413 "Template argument must be a reference or CopyConstructible type");
414 auto __p = any_cast<remove_reference_t<_ValueType>>(&__any);
415 if (__p)
416 return std::move(*__p);
417 __throw_bad_any_cast();
418 }
419 /// @}
420
421 /// @cond undocumented
422 template<typename _Tp>
424 __any_caster(const any* __any)
425 {
426 // any_cast<T> returns non-null if __any->type() == typeid(T) and
427 // typeid(T) ignores cv-qualifiers so remove them:
428 using _Up = remove_cv_t<_Tp>;
429 // The contained value has a decayed type, so if decay_t<U> is not U,
430 // then it's not possible to have a contained value of type U.
431 using __does_not_decay = is_same<decay_t<_Up>, _Up>;
432 // Only copy constructible types can be used for contained values.
433 using __is_copyable = is_copy_constructible<_Up>;
434 // If the type _Tp could never be stored in an any we don't want to
435 // instantiate _Manager<_Tp>, so use _Manager<any::_Op> instead, which
436 // is explicitly specialized and has a no-op _S_manage function.
437 using _Vp = __conditional_t<__and_<__does_not_decay, __is_copyable>{},
438 _Up, any::_Op>;
439 // First try comparing function addresses, which works without RTTI
440 if (__any->_M_manager == &any::_Manager<_Vp>::_S_manage
441#if __cpp_rtti
442 || __any->type() == typeid(_Tp)
443#endif
444 )
445 {
446 any::_Arg __arg;
447 __any->_M_manager(any::_Op_access, __any, &__arg);
448 return __arg._M_obj;
449 }
450 return nullptr;
451 }
452
453 // This overload exists so that std::any_cast<void(*)()>(a) is well-formed.
454 template<typename _Tp>
455 enable_if_t<!is_object<_Tp>::value, _Tp*>
456 __any_caster(const any*) noexcept
457 { return nullptr; }
458 /// @endcond
459
460 /**
461 * @brief Access the contained object.
462 *
463 * @tparam _ValueType The type of the contained object.
464 * @param __any A pointer to the object to access.
465 * @return The address of the contained object if <code>
466 * __any != nullptr && __any.type() == typeid(_ValueType)
467 * </code>, otherwise a null pointer.
468 *
469 * @{
470 */
471 template<typename _ValueType>
472 inline const _ValueType* any_cast(const any* __any) noexcept
473 {
474 if (__any)
475 return static_cast<_ValueType*>(__any_caster<_ValueType>(__any));
476 return nullptr;
477 }
478
479 template<typename _ValueType>
480 inline _ValueType* any_cast(any* __any) noexcept
481 {
482 if (__any)
483 return static_cast<_ValueType*>(__any_caster<_ValueType>(__any));
484 return nullptr;
485 }
486 /// @}
487
488 template<typename _Tp>
489 void
490 any::_Manager_internal<_Tp>::
491 _S_manage(_Op __which, const any* __any, _Arg* __arg)
492 {
493 // The contained object is in _M_storage._M_buffer
494 auto __ptr = reinterpret_cast<const _Tp*>(&__any->_M_storage._M_buffer);
495 switch (__which)
496 {
497 case _Op_access:
498 __arg->_M_obj = const_cast<_Tp*>(__ptr);
499 break;
500 case _Op_get_type_info:
501#if __cpp_rtti
502 __arg->_M_typeinfo = &typeid(_Tp);
503#endif
504 break;
505 case _Op_clone:
506 ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr);
507 __arg->_M_any->_M_manager = __any->_M_manager;
508 break;
509 case _Op_destroy:
510 __ptr->~_Tp();
511 break;
512 case _Op_xfer:
513 ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp
514 (std::move(*const_cast<_Tp*>(__ptr)));
515 __ptr->~_Tp();
516 __arg->_M_any->_M_manager = __any->_M_manager;
517 const_cast<any*>(__any)->_M_manager = nullptr;
518 break;
519 }
520 }
521
522 template<typename _Tp>
523 void
524 any::_Manager_external<_Tp>::
525 _S_manage(_Op __which, const any* __any, _Arg* __arg)
526 {
527 // The contained object is *_M_storage._M_ptr
528 auto __ptr = static_cast<const _Tp*>(__any->_M_storage._M_ptr);
529 switch (__which)
530 {
531 case _Op_access:
532 __arg->_M_obj = const_cast<_Tp*>(__ptr);
533 break;
534 case _Op_get_type_info:
535#if __cpp_rtti
536 __arg->_M_typeinfo = &typeid(_Tp);
537#endif
538 break;
539 case _Op_clone:
540 __arg->_M_any->_M_storage._M_ptr = new _Tp(*__ptr);
541 __arg->_M_any->_M_manager = __any->_M_manager;
542 break;
543 case _Op_destroy:
544 delete __ptr;
545 break;
546 case _Op_xfer:
547 __arg->_M_any->_M_storage._M_ptr = __any->_M_storage._M_ptr;
548 __arg->_M_any->_M_manager = __any->_M_manager;
549 const_cast<any*>(__any)->_M_manager = nullptr;
550 break;
551 }
552 }
553
554 // Dummy specialization used by __any_caster.
555 template<>
556 struct any::_Manager_internal<any::_Op>
557 {
558 static void
559 _S_manage(_Op, const any*, _Arg*) { }
560 };
561
562 /// @} group any
563} // namespace fundamentals_v1
564} // namespace experimental
565
566_GLIBCXX_END_NAMESPACE_VERSION
567} // namespace std
568
569#endif // C++14
570
571#endif // _GLIBCXX_EXPERIMENTAL_ANY
typename enable_if< _Cond, _Tp >::type enable_if_t
Alias template for enable_if.
Definition type_traits:2836
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:138
_ValueType any_cast(const any &__any)
Access the contained object.
ISO C++ entities toplevel namespace is std.
Part of RTTI.
Definition typeinfo:94
Thrown during incorrect typecasting.
Definition typeinfo:225
Define a member typedef type only if a boolean constant is true.
Definition type_traits:134
is_lvalue_reference
Definition type_traits:581
is_copy_constructible
Definition type_traits:1194
Exception class thrown by a failed any_cast.
virtual const char * what() const noexcept
A type-safe container of any type.
bool empty() const noexcept
Reports whether there is a contained object or not.
any(const any &__other)
Copy constructor, copies the state of __other.
any(any &&__other) noexcept
Move constructor, transfer the state from __other.
any & operator=(any &&__rhs) noexcept
Move assignment operator.
const type_info & type() const noexcept
The typeid of the contained object, or typeid(void) if empty.
void clear() noexcept
If not empty, destroy the contained object.
any() noexcept
Default constructor, creates an empty object.
void swap(any &__rhs) noexcept
Exchange state with another object.
any & operator=(const any &__rhs)
Copy the state of another object.
any(_ValueType &&__value)
Construct with a copy of __value as the contained object.
enable_if_t<!is_same< any, decay_t< _ValueType > >::value, any & > operator=(_ValueType &&__rhs)
Store a copy of __rhs as the contained object.