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