| [library Boost.TypeIndex |
| [quickbook 1.6] |
| [version 4.0] |
| [copyright 2012-2014 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. |
| |
| 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/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] |
| |
| [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] |