[library Boost.TypeIndex
    [quickbook 1.6]
    [version 4.2]
    [copyright 2012-2025 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 C++20 module]

[caution C++20 module support is on early stage, targets, flags and behavior may change in the future]

If using modern CMake define CMake option `-DBOOST_USE_MODULES=1` to build a C++20 module and
make the `Boost::type_index` CMake target provide it. After that an explicit usage of C++20 module `boost.type_index` is allowed:

[import ../modules/usage_sample.cpp]
[type_index_module_example]

The `Boost::type_index` CMake target gives an ability to mix includes and imports of the library in different translation units. Moreover,
if `BOOST_USE_MODULES` macro is defined then all the `boost/type_index/...` includes implicilty do `import boost.type_index;` to give all the
benifits of modules without changing the existing code.

[note For better compile times make sure that `import std;` is available when building the `boost.type_index` module (in CMake logs there should be
      a 'Using `import std;`' message). ]

If not using CMake, then the module could be build manually from the `modules/boost_type_index.cppm` file.

For manual module build the following commands can be used for clang compiler:

```
cd type_index/modules
clang++ -I ../include -std=c++20 --precompile -x c++-module boost_type_index.cppm
```

After that, the module could be used in the following way:

```
clang++ -std=c++20 -fmodule-file=boost_type_index.pcm boost_type_index.pcm usage_sample.cpp
```

[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]
