The ext::any github project: https://github.com/erez-strauss/ext_any/
The CppCon 2024 Open Content presentation slides: ext_any_presentation_CppCon2024_OpenContent_u20240930.pdf
Example on compiler explorer: https://compiler-explorer.com/z/5ErEPbEah
ext::any<N, Features ...> - is an owning container type that holds any type the programmers place into it. if the placed item fits into N bytes, it will be stored in place without dynamic memory allocation, otherwise it will be stored on the heap.
The standard std::any provides a similar storing and accessing capabilities, which were the base for the ext::any<> type definitions. The standard std::any requires the programmer to get the specific type in order to act on the stored value.
The ext::any::any<> provides the framework to use efficiently type erasure to act on the stored value and do generic operations on the stored values without knowing which specific type is stored in the ext::any<>
Different features can be activated as part of the specific ext::any, there are few defined features, while the user can define their own new features to be included in the ext::any types.
for example the following code works:
// example1.cpp
ext::any::any<16, Streamed> a0 (125);
std::cout << "a0: " << a0 << '\n'; // prints: a0: 125
a0 = "hello world";
std::cout << "a0: " << a0 << '\n'; // prints: a0: hello world
Usage example code
#include <any/any.h>
using namespace ext::any;
using any_one = any_type<16, af_streamed, af_strict_hash, af_strict_eq>; // Movable, Copyable - default.
any_one a0 {};
any_one a1 { std::type_inplace<double>, 111}; // holds a double.
any_one a2 { a0 };
any_one a3 { std::move ( a1 )}; // a3 double with value 111, a1 has no value.
// any_one a4 = { 1, 2.3, "bla bla" }; // a4 holds vector of any_one, each initialized. a4.size() return the vector size. -- tobe implemented.
auto a5 = a4; // copy the vector
auto a6 = std::move(a4); // moves the content of the a4 vector, a4 has no value.
C++ supports runtime type information, available at compile time through typeid().
The ext::any supports the type() function when RTTI is available, which is the default on most systems
On systems without RTTI, for example when compiling the code with '-fno-rtti' the ext::any will provide all its functionality which do not depend on the RTTI availability, including the cast_any(). If you need this functionality, see the no-rtti preset config.
The std::any is used only to store and retrieve object of different type, without a simple way to add actions to the type.
The ext::any::any<> provides the following features:
- ext::af_streamed – adds support for operator '<<' -- relaxed, print nothing if type is not printable
- ext::af_strict_streamed - does not accept values that do not support ‘<<’ -- all objects inside the any<> must have the '<<' operator on them.
- ext::af_strict_less – add support for less ‘<’ compare -- all object in any<> have '<' less than operator, so the any<> can be used in std::map<> or std::set<>
- ext::af_strict_eq - add support for ‘==’
- ext::af_strict_inplace - prevents using dynamic memory allocation
- ext::af_strict_hash – support hash value -- all objects inside the any<> can generate hash value, so this any<> variables can be used as key for std::unordered_set<> and std::unordered_map<>
- ext::af_variant - restrict the values to specific types
- ext::af_func - support operator ’()’ with different Args, not implemented yet
- ext::af_strict_add - the plus '+' operator -- the type in the any<> must have plus operator defined
The following are features that not yet implemented
- ext::af_allocator - use specific allocator to allocate the object types in case we need dynamic heap allocation.
- ext::af_vector - the any<> can contain a vector of any<> - so it can hold sub element, and has the function size() which returns the vector size
- ext::af_func - enable the any to hold functions and have the function call operator.
- ext::af_map - Add the insert(K,V) - so an any<> can hold a map of elements, a pair of key and value which are also any<>
Than with a compile time size of the small object optimization. ext::any<8> - maximum size of 8 bytes of inplace stored data. ext::any<32> - maximum size of the inplace stored data is 32. the size of the ext::any is N+8 bytes, as any need to hold a pointer to const struct with the support operations. The alignment requirements of the ext::any is by default 8 bytes.
Pay attention to std::in_place_type - as constructor in place for std::any
https://en.cppreference.com/w/cpp/utility/any
- constructors - empty, with value, with tag, with tag and value(s)
- assignment '=' from T types, or from Any, of the same template parameters, from Any of different template parameters.
- destructor - should call the appropriate type destructor
- emplace
- reset
- swap
- has_value
- type - returns typeid
- any_cast - friend - two cases, with pointer null if wrong type, T value throw if now correct type.
- constructor with any value type
- Constructor with type tag and optional value
- any_cast - returns a reference to the type or throw exception
- any_cast<T*> - returns a pointer to the value or nullptr
- Is there? a similar to visit call one of given functors in an object selected by the content type?
- not required to provide SSO, with any given size.
- std::make_any()
Basic new functionality, before the Features ...
- type_name
- is_dynamic() / is_inplace()
- add test, compare to std::any, verify / define af_* features.
- Add more google-tests, check for memory leaks, using sanitizers.
- add internal vector<ext::any> for std::initializer_list
- add Small String optimization zstring. to hold upto (N-1) null terminated string
- assignment from "literal string" - to convert to std::string
- copy / move, constructor / assignment from other ext::any<M, ...>
- All functionality of std::any (with cast_any() returning reference instead of value)
- SSO for size N.
- Additional functionality for different features: 5. formattable - support format ("this is the value in any: {}", a0); 6. comparison 7. initialisation - from initializer list - where each item is an any by itself ... 8. Vector container - add size function which tell if there is single data item or multiple any items. ( or other items? ) 9. Map 10. Func<R, ()> 11. user defined features.
-
Change the type name of the ext::any , please suggest in the github discussions.
-
Volunteers are welcome
-
Write emplace() that support
std::in_place_type
-
Add more compiler-explorer examples, for example: https://compiler-explorer.com/z/5ErEPbEah
-
Update this README.md
-
Define ext::any goals and more use cases
-
write more examples
-
Test / port to different platforms, Windows ...
-
As it is not just the base std::any API: 3. constructor with value 4. constructor with tagged_type - the standard one and our own. 5. bool has_value() 6. reset 7. non const access to the value_type 8. type() - return type_id
-
What features of std::variant we want to provide? visitor type access. ? problematic as at compile time no effective way to know what types are expected
-
packaging a vcpkg
Testing Basic Standard Functionality:
Default constructor - empty: has_value() - false, casting is failing, and type() returns typeinfo<void>
std::any
With small int
With larger data type.
any::~any
Observers
any::has_value
any::type
any::operator= -- replace value , verify no memory leaks with valgrind.
assign a value, and assign another any.
Modifiers
any::emplace
any::reset
any::swap
Non-member functions
swap(std::any)
any_cast
make_any
Helper classes
bad_any_cast
- Boost Any -- https://www.boost.org/doc/libs/1_85_0/doc/html/any.html
- poco Any -- https://docs.pocoproject.org/current/Poco.Any.html
- llvm libc++ any -- https://github.com/llvm/llvm-project/blob/main/libcxx/include/any
- gcc libstdc++ any -- https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/any