1[library Boost.TypeIndex
2    [quickbook 1.6]
3    [version 4.0]
4    [copyright 2012-2014 Antony Polukhin]
5    [category Language Features Emulation]
6    [license
7        Distributed under the Boost Software License, Version 1.0.
8        (See accompanying file LICENSE_1_0.txt or copy at
9        [@http://www.boost.org/LICENSE_1_0.txt])
10    ]
11]
12
13[section Motivation]
14Sometimes 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:
15
16* `typeid(T)` and `std::type_index` require Run Time Type Info (RTTI)
17* some implementations of `typeid(T)` erroneously do not strip const, volatile and references from type
18* some compilers have bugs and do not correctly compare `std::type_info` objects across shared libraries
19* only a few implementations of Standard Library currently provide `std::type_index`
20* no easy way to store type info without stripping const, volatile and references
21* no nice and portable way to get human readable type names
22* no way to easily make your own type info class
23
24Boost.TypeIndex library was designed to work around all those issues.
25
26[note `T` means type here. Think of it as of `T` in `template <class T>` ]
27
28[endsect]
29
30[section Getting started]
31
32[classref boost::typeindex::type_info boost::typeindex::type_info] is a drop-in replacement for `std::type_info` and
33[classref boost::typeindex::type_index boost::typeindex::type_index]
34is a drop-in replacement for `std::type_index`. Unlike Standard Library versions those classes can work without RTTI.
35
36`type_index` provides the full set of comparison operators, hashing functions and ostream
37operators, so it can be used with any container class.
38
39[section How to use]
40
41To start using Boost.TypeIndex:
42
43[table:porting
44[[Replace this:][With the following:][More Info]]
45[[``
46    #include <typeinfo>
47    #include <typeindex>
48``][``
49    #include <boost/type_index.hpp>
50``][
51    [headerref boost/type_index.hpp more... ]
52]]
53
54[[``
55    std::type_index
56``][``
57    boost::typeindex::type_index
58``][
59    [classref boost::typeindex::type_index more... ]
60]]
61
62[[``
63    typeid(T)
64    typeid(T).name() // not human readable
65    typeid(variable)
66``][``
67    boost::typeindex::type_id<T>()
68    boost::typeindex::type_id<T>().pretty_name() // human readable
69    boost::typeindex::type_id_runtime(variable)
70``][
71    [funcref boost::typeindex::type_id more... ]
72
73    [classref boost::typeindex::type_index more... ]
74
75    [funcref boost::typeindex::type_id_runtime more... ]
76]]
77
78[[``
79    // attempt to save const, volatile, reference
80    typeid(please_save_modifiers<T>)
81``][``
82    // cvr = const, volatile, reference
83    boost::typeindex::type_id_with_cvr<T>()
84``][
85    [funcref boost::typeindex::type_id_with_cvr more... ]
86]]
87
88[[``
89    // when reference to `std::type_info` is required
90    const std::type_info& v1 = typeid(int);
91
92    // other cases
93    const std::type_info* v2 = &typeid(int);
94``][``
95    const boost::typeindex::type_info& v1
96        = boost::typeindex::type_id<int>().type_info();
97
98    boost::typeindex::type_index v2
99        = boost::typeindex::type_id<int>();
100``][
101    [classref boost::typeindex::type_index more... ]
102
103    [funcref boost::typeindex::type_id more... ]
104]]
105]
106
107If you are using [funcref boost::typeindex::type_id_runtime type_id_runtime()] methods
108and RTTI is disabled, make sure that classes that are passed to
109`type_id_runtime()` are marked with
110[macroref BOOST_TYPE_INDEX_REGISTER_CLASS BOOST_TYPE_INDEX_REGISTER_CLASS] macro.
111
112[endsect]
113
114[section Example with Boost.Any]
115
116Here is how TypeIndex could be used in `boost/any.hpp`:
117[table:any
118[[Before] [With TypeIndex]]
119[[``#include <typeinfo>``][``#include <boost/type_index.hpp>``]]
120[[``
121    virtual const std::type_info & type() const BOOST_NOEXCEPT
122    {
123        // requires RTTI
124        return typeid(ValueType);
125    }
126``] [``
127    virtual const boost::typeindex::type_info & type() const BOOST_NOEXCEPT
128    {
129        // now works even with RTTI disabled
130        return boost::typeindex::type_id<ValueType>().type_info();
131    }
132``]]
133]
134
135[endsect]
136
137
138[section Example with Boost.Variant]
139
140Here is how TypeIndex could be used in `boost/variant/variant.hpp`:
141[table:variant
142[[Before] [With TypeIndex]]
143
144[[``
145#if !defined(BOOST_NO_TYPEID)
146#include <typeinfo> // for typeid, std::type_info
147#endif // BOOST_NO_TYPEID
148``][``
149#include <boost/type_index.hpp>
150``]]
151[[``
152#if !defined(BOOST_NO_TYPEID)
153
154class reflect
155    : public static_visitor<const std::type_info&>
156{
157public: // visitor interfaces
158
159    template <typename T>
160    const std::type_info& operator()(const T&) const BOOST_NOEXCEPT
161    {
162        return typeid(T);
163    }
164
165};
166
167#endif // BOOST_NO_TYPEID
168``][``
169class reflect
170    : public static_visitor<const boost::typeindex::type_info&>
171{
172public: // visitor interfaces
173
174    template <typename T>
175    const boost::typeindex::type_info& operator()(const T&) const BOOST_NOEXCEPT
176    {
177        return boost::typeindex::type_id<T>().type_info();
178    }
179
180};
181``]]
182[[``
183#if !defined(BOOST_NO_TYPEID)
184    const std::type_info& type() const
185    {
186        detail::variant::reflect visitor;
187        return this->apply_visitor(visitor);
188    }
189#endif
190``] [``
191    const boost::typeindex::type_info& type() const
192    {
193        detail::variant::reflect visitor;
194        return this->apply_visitor(visitor);
195    }
196``]]
197]
198
199[endsect]
200[endsect]
201
202[section:config Configuring and building the library]
203
204TypeIndex is a header only library and it does not use Boost libraries that require
205building. You just need to `#include <boost/type_index.hpp>` to start using it.
206
207The library supports a number of configuration macros, defining which require full
208rebuild of all the projects that use TypeIndex:
209
210[table Configuration macros
211    [[Macro name]                                               [Short description]]
212    [[[macroref BOOST_TYPE_INDEX_USER_TYPEINDEX]]               [ Macro that allows you to use your
213own implementation of TypeIndex instead of the default all around the projects and libraries.]]
214
215    [[[macroref BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY]]  [ Macro that must be defined
216if you are mixing RTTI-on and RTTI-off.]]
217
218    [[[macroref BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING] and
219[macroref BOOST_TYPE_INDEX_FUNCTION_SIGNATURE]]                 [ Macros that allow you to specify
220parsing options and type name generating macro for RTTI-off cases. ]]
221]
222
223You can define configuration macros in the `bjam` command line using one of the following
224approaches:
225
226[pre
227    b2 variant=release define=BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY stage
228]
229
230[pre
231    b2 variant=release "define=BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING='(39, 1, true, \\"T = \\")'" stage
232]
233
234However, it may be more convenient to define configuration macros in the "boost/config/user.hpp"
235file in order to automatically define them both for the library and user's projects.
236
237[endsect]
238
239[section How it works]
240`type_index` is just a typedef for [classref boost::typeindex::stl_type_index]
241or [classref boost::typeindex::ctti_type_index].
242
243Depending on the `typeid()` availability TypeIndex library will choose an optimal class for
244`type_index`. In cases when at least basic support for `typeid()` is available `stl_type_index` will be used.
245
246[macroref BOOST_TYPE_INDEX_REGISTER_CLASS] macro is a helper macro that places some virtual helper functions or
247expands to nothing.
248
249Issues with cross module type comparison on a bugged compilers are bypassed by directly comparing strings with type
250(latest versions of those compilers resolved that issue using exactly the same approach).
251
252[endsect]
253
254[section Examples]
255
256[import ../examples/demangled_names.cpp]
257[section Getting human readable and mangled type names] [type_index_names_example] [endsect]
258
259[import ../examples/registry.cpp]
260[section Storing information about a type in container ] [type_index_registry_example] [endsect]
261
262[import ../examples/inheritance.cpp]
263[section Getting through the inheritance to receive a real type name ] [type_index_derived_example] [endsect]
264
265[import ../examples/exact_types_match.cpp]
266[section Exact type matching: storing type with const, volatile and reference qualifiers] [type_index_exact_type_match_example] [endsect]
267
268[import ../examples/table_of_names.cpp]
269[section Table of raw_name() and pretty_name() outputs with and without RTTI ] [type_index_names_table] [endsect]
270
271[endsect]
272
273[xinclude autodoc.xml]
274
275[section Making a custom type_index]
276
277Sometimes 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.
278
279[import ../examples/user_defined_typeinfo.hpp]
280[import ../examples/user_defined_typeinfo.cpp]
281
282[section Basics]
283[type_index_userdefined_usertypes]
284[type_index_userdefined_enum]
285[type_index_my_type_index]
286[type_index_my_type_index_usage]
287[endsect]
288
289[section Getting type infos at runtime]
290[type_index_my_type_index_register_class]
291[type_index_my_type_index_type_id_runtime_implmentation]
292[type_index_my_type_index_type_id_runtime_classes]
293[type_index_my_type_index_type_id_runtime_test]
294[endsect]
295
296[section Using new type infos all around the code]
297[type_index_my_type_index_worldwide_macro]
298[type_index_my_type_index_worldwide_typedefs]
299[type_index_my_type_index_worldwide_usage]
300[endsect]
301
302[endsect]
303
304
305[section Space and Performance]
306
307* `ctti_type_index` uses macro for getting full text representation of function name which could lead to code bloat,
308so prefer using `stl_type_index` type when possible.
309* All the type_index classes hold a single pointer and are fast to copy.
310* 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.
311* Comparison operators are optimized as much as possible and execute a single `std::strcmp` in worst case.
312* 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.
313
314[endsect]
315
316[section Code bloat]
317
318Without RTTI TypeIndex library will switch from using `boost::typeindex::stl_type_index` class to
319`boost::typeindex::ctti_type_index`. `boost::typeindex::ctti_type_index` uses macro for getting full
320text representation of function name for each type that is passed to `type_id()` and
321`type_id_with_cvr()` functions.
322
323This leads to big strings in binary file:
324```
325static const char* boost::detail::ctti<T>::n() [with T = int]
326static const char* boost::detail::ctti<T>::n() [with T = user_defined_type]
327```
328While using RTTI, you'll get the following (more compact) string in binary file:
329
330```
331i
33217user_defined_type
333```
334
335[endsect]
336
337[section RTTI emulation limitations]
338
339TypeIndex has been tested and successfully work on many compilers.
340
341[warning
342    With RTTI off classes with exactly the same names defined in different modules in anonymous namespaces may collapse:
343    ```
344    // In A.cpp
345    namespace { struct user_defined{}; }
346    type_index foo_a() { return type_id<user_defined>(); }
347
348    // In B.cpp
349    namespace { struct user_defined{}; }
350    type_index foo_b() { return type_id<user_defined>(); }
351
352    // In main.cpp
353    assert(foo_a() != foo_b()); // will fail on some compilers
354    ```
355
356    *Compilers that have that limitation:* GCC, CLANG, Intel.
357
358    *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.
359]
360
361[section Define the BOOST_TYPE_INDEX_FUNCTION_SIGNATURE macro]
362
363If you get the following error during compilation
364``
365            TypeIndex library could not detect your compiler.
366            Please make the BOOST_TYPE_INDEX_FUNCTION_SIGNATURE macro use
367            correct compiler macro for getting the whole function name.
368            Define BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING to correct value after that.
369``
370then you are using a compiler that was not tested with this library.
371
372[macroref BOOST_TYPE_INDEX_FUNCTION_SIGNATURE] must be defined to a compiler specific macro, that outputs the *whole*
373function signature including template parameters.
374
375
376[endsect]
377
378[section Fixing pretty_name() output]
379
380If the output of `boost::typeindex::ctti_type_index::type_id<int>().name()`
381* returns not just `int` but also a lot of text around the `int`
382* or does not return type at all
383then you are using a compiler that was not tested with this library and you need to setup the
384[macroref BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING] macro.
385
386Here is a short instruction:
387
388# get the output of `boost::typeindex::ctti_type_index::type_id<int>().name()`
389# define [macroref BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING] to
390`(skip_at_begin, skip_at_end, false, "")`, where
391    * `skip_at_begin` is equal to characters count before the first occurrence of `int` in output
392    * `skip_at_end` is equal to characters count after last occurrence of `int` in output
393# check that `boost::typeindex::ctti_type_index::type_id<int>().name_demangled()` returns "int"
394# if it does not return `int`, then define BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING to
395`(skip_at_begin, skip_at_end, true, "T = ")`, where
396    * `skip_at_begin` is equal to `skip_at_begin` at step 2
397    * `skip_at_end` is equal to `skip_at_end` at step 2
398    * `"T = "` is equal to characters that are right before the `int` in output
399# (optional, but highly recommended) [@http://www.boost.org/support/bugs.html create ticket] with
400feature request to add your compiler to supported compilers list. Include
401parameters provided to `BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING` macro.
402
403
404Consider the following example:
405
406`boost::typeindex::ctti_type_index::type_id<int>().raw_name()` returns
407"const char *__cdecl boost::detail::ctti<int>::n(void)". Then you shall set
408`skip_at_begin` to `sizeof("const char *__cdecl boost::detail::ctti<") - 1`
409and `skip_at_end` to `sizeof(">::n(void)") - 1`.
410
411``
412#define BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING (39, 6, false, "")
413``
414
415Another example:
416
417`boost::typeindex::ctti_type_index::type_id<int>().raw_name()` returns
418"static const char *boost::detail::ctti<int>::n() [T = int]"". Then you shall set
419`skip_at_begin` to `sizeof("static const char *boost::detail::ctti<") - 1`
420and `skip_at_end` to `sizeof("]") - 1` and last parameter of macro to "T = ".
421
422``
423#define BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING (39, 1, true, "T = ")
424``
425
426[endsect]
427
428[endsect]
429
430[section Mixing sources with RTTI on and RTTI off]
431
432Linking a binary from source files that were compiled with different RTTI flags is not a very good
433idea and may lead to a lot of surprises. However if there is a very strong need, TypeIndex library
434provides a solution for mixing sources: just define [macroref BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY]
435macro. This would lead to usage of same type_index class (`boost::typeindex::ctti_type_index` or
436`boost::typeindex::stl_type_index`) all around the project.
437
438[note Do not forget to rebuild *all* the projects with `BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY` macro defined ]
439
440You must know that linking RTTI on and RTTI off binaries may succeed even without defining the
441`BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY` macro, but that does not mean that you'll get a
442working binary. Such actions may break the One Definition Rule. Take a look at the table below,
443that shows how the `boost::type_index get_integer();` function will look like with different
444RTTI flags:
445
446[table:diffs
447[[RTTI on] [RTTI off]]
448[[`boost::typeindex::stl_type_index get_integer();`] [`boost::typeindex::ctti_type_index get_integer();`]]
449]
450
451Such differences are usually not detected by linker and lead to errors at runtime.
452
453[warning
454    Even with `BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY` defined there is no guarantee
455    that everything will be OK. Libraries that use their own workarounds for disabled RTTI
456    may fail to link or to work correctly.
457]
458
459[endsect]
460
461[section Acknowledgements]
462
463In order of helping and advising:
464
465* Peter Dimov for writing source codes in late 2007, that gave me an idea of how to emulate RTTI.
466* Agustín Bergé K-ballo for helping with docs and fixing a lot of typos.
467* Niall Douglas for generating a lot of great ideas, reviewing the sources and being the review manager for the library.
468* All the library reviewers, especially Andrey Semashev, for making good notes and proposing improvements to the library.
469
470[endsect]
471