123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- [library Boost.TypeIndex
- [quickbook 1.6]
- [version 4.1]
- [copyright 2012-2019 Antony Polukhin]
- [category Language Features Emulation]
- [license
- Distributed under the Boost Software License, Version 1.0.
- (See accompanying file LICENSE_1_0.txt or copy at
- [@http://www.boost.org/LICENSE_1_0.txt])
- ]
- ]
- [section Motivation]
- Sometimes getting and storing information about a type at runtime is required. For such cases a construction like `&typeid(T)` or C++11 class `std::type_index` is usually used, which is where problems start:
- * `typeid(T)` and `std::type_index` require Run Time Type Info (RTTI)
- * some implementations of `typeid(T)` erroneously do not strip const, volatile and references from type
- * some compilers have bugs and do not correctly compare `std::type_info` objects across shared libraries
- * only a few implementations of Standard Library currently provide `std::type_index`
- * no easy way to store type info without stripping const, volatile and references
- * no nice and portable way to get human readable type names
- * no way to easily make your own type info class
- Boost.TypeIndex library was designed to work around all those issues.
- [note `T` means type here. Think of it as of `T` in `template <class T>` ]
- [endsect]
- [section Getting started]
- [classref boost::typeindex::type_info boost::typeindex::type_info] is a drop-in replacement for `std::type_info` and
- [classref boost::typeindex::type_index boost::typeindex::type_index]
- is a drop-in replacement for `std::type_index`. Unlike Standard Library versions those classes can work without RTTI.
- `type_index` provides the full set of comparison operators, hashing functions and ostream
- operators, so it can be used with any container class.
- [section How to use]
- To start using Boost.TypeIndex:
- [table:porting
- [[Replace this:][With the following:][More Info]]
- [[``
- #include <typeinfo>
- #include <typeindex>
- ``][``
- #include <boost/type_index.hpp>
- ``][
- [headerref boost/type_index.hpp more... ]
- ]]
- [[``
- std::type_index
- ``][``
- boost::typeindex::type_index
- ``][
- [classref boost::typeindex::type_index more... ]
- ]]
- [[``
- typeid(T)
- typeid(T).name() // not human readable
- typeid(variable)
- ``][``
- boost::typeindex::type_id<T>()
- boost::typeindex::type_id<T>().pretty_name() // human readable
- boost::typeindex::type_id_runtime(variable)
- ``][
- [funcref boost::typeindex::type_id more... ]
- [classref boost::typeindex::type_index more... ]
- [funcref boost::typeindex::type_id_runtime more... ]
- ]]
- [[``
- // attempt to save const, volatile, reference
- typeid(please_save_modifiers<T>)
- ``][``
- // cvr = const, volatile, reference
- boost::typeindex::type_id_with_cvr<T>()
- ``][
- [funcref boost::typeindex::type_id_with_cvr more... ]
- ]]
- [[``
- // when reference to `std::type_info` is required
- const std::type_info& v1 = typeid(int);
- // other cases
- const std::type_info* v2 = &typeid(int);
- ``][``
- const boost::typeindex::type_info& v1
- = boost::typeindex::type_id<int>().type_info();
- boost::typeindex::type_index v2
- = boost::typeindex::type_id<int>();
- ``][
- [classref boost::typeindex::type_index more... ]
- [funcref boost::typeindex::type_id more... ]
- ]]
- ]
- If you are using [funcref boost::typeindex::type_id_runtime type_id_runtime()] methods
- and RTTI is disabled, make sure that classes that are passed to
- `type_id_runtime()` are marked with
- [macroref BOOST_TYPE_INDEX_REGISTER_CLASS BOOST_TYPE_INDEX_REGISTER_CLASS] macro.
- [endsect]
- [section Example with Boost.Any]
- Here is how TypeIndex could be used in `boost/any.hpp`:
- [table:any
- [[Before] [With TypeIndex]]
- [[``#include <typeinfo>``][``#include <boost/type_index.hpp>``]]
- [[``
- virtual const std::type_info & type() const BOOST_NOEXCEPT
- {
- // requires RTTI
- return typeid(ValueType);
- }
- ``] [``
- virtual const boost::typeindex::type_info & type() const BOOST_NOEXCEPT
- {
- // now works even with RTTI disabled
- return boost::typeindex::type_id<ValueType>().type_info();
- }
- ``]]
- ]
- [endsect]
- [section Example with Boost.Variant]
- Here is how TypeIndex could be used in `boost/variant/variant.hpp`:
- [table:variant
- [[Before] [With TypeIndex]]
- [[``
- #if !defined(BOOST_NO_TYPEID)
- #include <typeinfo> // for typeid, std::type_info
- #endif // BOOST_NO_TYPEID
- ``][``
- #include <boost/type_index.hpp>
- ``]]
- [[``
- #if !defined(BOOST_NO_TYPEID)
- class reflect
- : public static_visitor<const std::type_info&>
- {
- public: // visitor interfaces
- template <typename T>
- const std::type_info& operator()(const T&) const BOOST_NOEXCEPT
- {
- return typeid(T);
- }
- };
- #endif // BOOST_NO_TYPEID
- ``][``
- class reflect
- : public static_visitor<const boost::typeindex::type_info&>
- {
- public: // visitor interfaces
- template <typename T>
- const boost::typeindex::type_info& operator()(const T&) const BOOST_NOEXCEPT
- {
- return boost::typeindex::type_id<T>().type_info();
- }
- };
- ``]]
- [[``
- #if !defined(BOOST_NO_TYPEID)
- const std::type_info& type() const
- {
- detail::variant::reflect visitor;
- return this->apply_visitor(visitor);
- }
- #endif
- ``] [``
- const boost::typeindex::type_info& type() const
- {
- detail::variant::reflect visitor;
- return this->apply_visitor(visitor);
- }
- ``]]
- ]
- [endsect]
- [endsect]
- [section:config Configuring and building the library]
- TypeIndex is a header only library and it does not use Boost libraries that require
- building. You just need to `#include <boost/type_index.hpp>` to start using it.
- The library supports a number of configuration macros, defining which require full
- rebuild of all the projects that use TypeIndex:
- [table Configuration macros
- [[Macro name] [Short description]]
- [[[macroref BOOST_TYPE_INDEX_USER_TYPEINDEX]] [ Macro that allows you to use your
- own implementation of TypeIndex instead of the default all around the projects and libraries.]]
- [[[macroref BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY]] [ Macro that must be defined
- if you are mixing RTTI-on and RTTI-off.]]
- [[[macroref BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING] and
- [macroref BOOST_TYPE_INDEX_FUNCTION_SIGNATURE]] [ Macros that allow you to specify
- parsing options and type name generating macro for RTTI-off cases. ]]
- ]
- You can define configuration macros in the `bjam` command line using one of the following
- approaches:
- [pre
- b2 variant=release define=BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY stage
- ]
- [pre
- b2 variant=release "define=BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING='(39, 1, true, \\"T = \\")'" stage
- ]
- However, it may be more convenient to define configuration macros in the "boost/config/user.hpp"
- file in order to automatically define them both for the library and user's projects.
- [endsect]
- [section How it works]
- `type_index` is just a typedef for [classref boost::typeindex::stl_type_index]
- or [classref boost::typeindex::ctti_type_index].
- Depending on the `typeid()` availability TypeIndex library will choose an optimal class for
- `type_index`. In cases when at least basic support for `typeid()` is available `stl_type_index` will be used.
- [macroref BOOST_TYPE_INDEX_REGISTER_CLASS] macro is a helper macro that places some virtual helper functions or
- expands to nothing.
- [macroref BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS] macro is a helper macro that places the same
- helpers as BOOST_TYPE_INDEX_REGISTER_CLASS plus some additional helpers for boost::typeindex::runtime_cast
- to function.
- Issues with cross module type comparison on a bugged compilers are bypassed by directly comparing strings with type
- (latest versions of those compilers resolved that issue using exactly the same approach).
- [endsect]
- [section Examples]
- [import ../examples/demangled_names.cpp]
- [section Getting human readable and mangled type names] [type_index_names_example] [endsect]
- [import ../examples/registry.cpp]
- [section Storing information about a type in container ] [type_index_registry_example] [endsect]
- [import ../examples/inheritance.cpp]
- [section Getting through the inheritance to receive a real type name ] [type_index_derived_example] [endsect]
- [import ../examples/runtime_cast.cpp]
- [section Using runtime_cast where RTTI is unavailable or undesirable ] [type_index_runtime_cast_example] [endsect]
- [import ../examples/exact_types_match.cpp]
- [section Exact type matching: storing type with const, volatile and reference qualifiers] [type_index_exact_type_match_example] [endsect]
- [import ../examples/table_of_names.cpp]
- [section Table of raw_name() and pretty_name() outputs with and without RTTI ] [type_index_names_table] [endsect]
- [import ../examples/constexpr14_namespace_check.cpp]
- [section C++14: Checking namespace at compile time ] [type_index_constexpr14_namespace_example] [endsect]
- [import ../examples/constexpr14_sort_check.cpp]
- [section C++14: Checking lexigraphical order of provided types ] [type_index_constexpr14_sort_check_example] [endsect]
- [endsect]
- [xinclude autodoc.xml]
- [section Making a custom type_index]
- Sometimes there may be a need to create your own type info system. This may be useful if you wish to store some more info about types (PODness, size of a type, pointers to common functions...) or if you have an idea of a more compact types representations.
- [import ../examples/user_defined_typeinfo.hpp]
- [import ../examples/user_defined_typeinfo.cpp]
- [section Basics]
- [type_index_userdefined_usertypes]
- [type_index_userdefined_enum]
- [type_index_my_type_index]
- [type_index_my_type_index_usage]
- [endsect]
- [section Getting type infos at runtime]
- [type_index_my_type_index_register_class]
- [type_index_my_type_index_type_id_runtime_implmentation]
- [type_index_my_type_index_type_id_runtime_classes]
- [type_index_my_type_index_type_id_runtime_test]
- [endsect]
- [section Using new type infos all around the code]
- [type_index_my_type_index_worldwide_macro]
- [type_index_my_type_index_worldwide_typedefs]
- [type_index_my_type_index_worldwide_usage]
- [endsect]
- [endsect]
- [section Space and Performance]
- * `ctti_type_index` uses macro for getting full text representation of function name which could lead to code bloat,
- so prefer using `stl_type_index` type when possible.
- * All the type_index classes hold a single pointer and are fast to copy.
- * Calls to `const char* raw_name()` do not require dynamic memory allocation and usually just return a pointer to an array of chars in a read-only section of the binary image.
- * Comparison operators are optimized as much as possible and execute a single `std::strcmp` in worst case.
- * Calls to `std::string pretty_name()` usually require dynamic memory allocation and some computations, so they are not recommended for usage in performance critical sections.
- [endsect]
- [section Code bloat]
- Without RTTI TypeIndex library will switch from using `boost::typeindex::stl_type_index` class to
- `boost::typeindex::ctti_type_index`. `boost::typeindex::ctti_type_index` uses macro for getting full
- text representation of function name for each type that is passed to `type_id()` and
- `type_id_with_cvr()` functions.
- This leads to big strings in binary file:
- ```
- static const char* boost::detail::ctti<T>::n() [with T = int]
- static const char* boost::detail::ctti<T>::n() [with T = user_defined_type]
- ```
- While using RTTI, you'll get the following (more compact) string in binary file:
- ```
- i
- 17user_defined_type
- ```
- [endsect]
- [section RTTI emulation limitations]
- TypeIndex has been tested and successfully work on many compilers.
- [warning
- With RTTI off classes with exactly the same names defined in different modules in anonymous namespaces may collapse:
- ```
- // In A.cpp
- namespace { struct user_defined{}; }
- type_index foo_a() { return type_id<user_defined>(); }
-
- // In B.cpp
- namespace { struct user_defined{}; }
- type_index foo_b() { return type_id<user_defined>(); }
-
- // In main.cpp
- assert(foo_a() != foo_b()); // will fail on some compilers
- ```
-
- *Compilers that have that limitation:* GCC, CLANG, Intel.
- *Test:* you can test this issue by runing the `testing_crossmodule_anonymous_no_rtti` that can be build if you run `../../../b2` in `type_index/test/` folder.
- ]
- [section Define the BOOST_TYPE_INDEX_FUNCTION_SIGNATURE macro]
- If you get the following error during compilation
- ``
- TypeIndex library could not detect your compiler.
- Please make the BOOST_TYPE_INDEX_FUNCTION_SIGNATURE macro use
- correct compiler macro for getting the whole function name.
- Define BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING to correct value after that.
- ``
- then you are using a compiler that was not tested with this library.
- [macroref BOOST_TYPE_INDEX_FUNCTION_SIGNATURE] must be defined to a compiler specific macro, that outputs the *whole*
- function signature including template parameters.
- [endsect]
- [section Fixing pretty_name() output]
- If the output of `boost::typeindex::ctti_type_index::type_id<int>().name()`
- * returns not just `int` but also a lot of text around the `int`
- * or does not return type at all
- then you are using a compiler that was not tested with this library and you need to setup the
- [macroref BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING] macro.
- Here is a short instruction:
- # get the output of `boost::typeindex::ctti_type_index::type_id<int>().name()`
- # define [macroref BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING] to
- `(skip_at_begin, skip_at_end, false, "")`, where
- * `skip_at_begin` is equal to characters count before the first occurrence of `int` in output
- * `skip_at_end` is equal to characters count after last occurrence of `int` in output
- # check that `boost::typeindex::ctti_type_index::type_id<int>().name_demangled()` returns "int"
- # if it does not return `int`, then define BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING to
- `(skip_at_begin, skip_at_end, true, "T = ")`, where
- * `skip_at_begin` is equal to `skip_at_begin` at step 2
- * `skip_at_end` is equal to `skip_at_end` at step 2
- * `"T = "` is equal to characters that are right before the `int` in output
- # (optional, but highly recommended) [@http://www.boost.org/support/bugs.html create ticket] with
- feature request to add your compiler to supported compilers list. Include
- parameters provided to `BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING` macro.
- Consider the following example:
- `boost::typeindex::ctti_type_index::type_id<int>().raw_name()` returns
- "const char *__cdecl boost::detail::ctti<int>::n(void)". Then you shall set
- `skip_at_begin` to `sizeof("const char *__cdecl boost::detail::ctti<") - 1`
- and `skip_at_end` to `sizeof(">::n(void)") - 1`.
- ``
- #define BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING (39, 6, false, "")
- ``
- Another example:
- `boost::typeindex::ctti_type_index::type_id<int>().raw_name()` returns
- "static const char *boost::detail::ctti<int>::n() [T = int]"". Then you shall set
- `skip_at_begin` to `sizeof("static const char *boost::detail::ctti<") - 1`
- and `skip_at_end` to `sizeof("]") - 1` and last parameter of macro to "T = ".
- ``
- #define BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING (39, 1, true, "T = ")
- ``
- [endsect]
- [endsect]
- [section Mixing sources with RTTI on and RTTI off]
- Linking a binary from source files that were compiled with different RTTI flags is not a very good
- idea and may lead to a lot of surprises. However if there is a very strong need, TypeIndex library
- provides a solution for mixing sources: just define [macroref BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY]
- macro. This would lead to usage of same type_index class (`boost::typeindex::ctti_type_index` or
- `boost::typeindex::stl_type_index`) all around the project.
- [note Do not forget to rebuild *all* the projects with `BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY` macro defined ]
- You must know that linking RTTI on and RTTI off binaries may succeed even without defining the
- `BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY` macro, but that does not mean that you'll get a
- working binary. Such actions may break the One Definition Rule. Take a look at the table below,
- that shows how the `boost::type_index get_integer();` function will look like with different
- RTTI flags:
- [table:diffs
- [[RTTI on] [RTTI off]]
- [[`boost::typeindex::stl_type_index get_integer();`] [`boost::typeindex::ctti_type_index get_integer();`]]
- ]
- Such differences are usually not detected by linker and lead to errors at runtime.
- [warning
- Even with `BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY` defined there is no guarantee
- that everything will be OK. Libraries that use their own workarounds for disabled RTTI
- may fail to link or to work correctly.
- ]
- [endsect]
- [section Acknowledgements]
- In order of helping and advising:
- * Peter Dimov for writing source codes in late 2007, that gave me an idea of how to emulate RTTI.
- * Agustín Bergé K-ballo for helping with docs and fixing a lot of typos.
- * Niall Douglas for generating a lot of great ideas, reviewing the sources and being the review manager for the library.
- * All the library reviewers, especially Andrey Semashev, for making good notes and proposing improvements to the library.
- [endsect]
|