summaryrefslogtreecommitdiff
path: root/libs/type_index/doc/type_index.qbk
blob: 27d8777ca691bc0f3eb052c3fc25cc857455e3d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
[library Boost.TypeIndex
    [quickbook 1.6]
    [version 4.1]
    [copyright 2012-2016 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]

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