[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 ` ] [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 #include ``][`` #include ``][ [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() boost::typeindex::type_id().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) ``][`` // cvr = const, volatile, reference boost::typeindex::type_id_with_cvr() ``][ [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().type_info(); boost::typeindex::type_index v2 = boost::typeindex::type_id(); ``][ [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 ``][``#include ``]] [[`` 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().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 // for typeid, std::type_info #endif // BOOST_NO_TYPEID ``][`` #include ``]] [[`` #if !defined(BOOST_NO_TYPEID) class reflect : public static_visitor { public: // visitor interfaces template const std::type_info& operator()(const T&) const BOOST_NOEXCEPT { return typeid(T); } }; #endif // BOOST_NO_TYPEID ``][`` class reflect : public static_visitor { public: // visitor interfaces template const boost::typeindex::type_info& operator()(const T&) const BOOST_NOEXCEPT { return boost::typeindex::type_id().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 ` 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::n() [with T = int] static const char* boost::detail::ctti::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(); } // In B.cpp namespace { struct user_defined{}; } type_index foo_b() { return type_id(); } // 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().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().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().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().raw_name()` returns "const char *__cdecl boost::detail::ctti::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().raw_name()` returns "static const char *boost::detail::ctti::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]