type_index.qbk 17 KB

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