user_defined_typeinfo.hpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // Copyright 2013-2019 Antony Polukhin
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See the accompanying file LICENSE_1_0.txt
  4. // or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
  5. #ifndef USER_DEFINED_TYPEINFO_HPP
  6. #define USER_DEFINED_TYPEINFO_HPP
  7. //[type_index_userdefined_usertypes
  8. /*`
  9. The following example shows how a user defined type_info can be created and used.
  10. Example works with and without RTTI.
  11. Consider situation when user uses only those types in `typeid()`:
  12. */
  13. #include <vector>
  14. #include <string>
  15. namespace my_namespace {
  16. class my_class;
  17. struct my_struct;
  18. typedef std::vector<my_class> my_classes;
  19. typedef std::string my_string;
  20. } // namespace my_namespace
  21. //] [/type_index_userdefined_usertypes]
  22. //[type_index_userdefined_enum
  23. /*`
  24. In that case user may wish to save space in binary and create it's own type system.
  25. For that case `detail::typenum<>` meta function is added. Depending on the input type T
  26. this function will return different numeric values.
  27. */
  28. #include <boost/type_index/type_index_facade.hpp>
  29. namespace my_namespace { namespace detail {
  30. template <class T> struct typenum;
  31. template <> struct typenum<void>{ enum {value = 0}; };
  32. template <> struct typenum<my_class>{ enum {value = 1}; };
  33. template <> struct typenum<my_struct>{ enum {value = 2}; };
  34. template <> struct typenum<my_classes>{ enum {value = 3}; };
  35. template <> struct typenum<my_string>{ enum {value = 4}; };
  36. #ifdef BOOST_MSVC
  37. #pragma warning(push)
  38. #pragma warning(disable: 4510 4512 4610) // non-copyable non-constructable type
  39. #endif
  40. // my_typeinfo structure is used to save type number
  41. struct my_typeinfo {
  42. const char* const type_;
  43. };
  44. #ifdef BOOST_MSVC
  45. #pragma warning(pop)
  46. #endif
  47. const my_typeinfo infos[5] = {
  48. {"void"}, {"my_class"}, {"my_struct"}, {"my_classes"}, {"my_string"}
  49. };
  50. template <class T>
  51. inline const my_typeinfo& my_typeinfo_construct() {
  52. return infos[typenum<T>::value];
  53. }
  54. }} // my_namespace::detail
  55. //] [/type_index_userdefined_usertypes]
  56. //[type_index_my_type_index
  57. /*`
  58. `my_type_index` is a user created type_index class. If in doubt during this phase, you can always
  59. take a look at the `<boost/type_index/ctti_type_index.hpp>` or `<boost/type_index/stl_type_index.hpp>`
  60. files. Documentation for `type_index_facade` could be also useful.
  61. */
  62. /*`
  63. Since we are not going to override `type_index_facade::hash_code()` we must additionally include
  64. `<boost/container_hash/hash.hpp>`.
  65. */
  66. #include <boost/container_hash/hash.hpp>
  67. /*`
  68. See implementation of `my_type_index`:
  69. */
  70. namespace my_namespace {
  71. class my_type_index: public boost::typeindex::type_index_facade<my_type_index, detail::my_typeinfo> {
  72. const detail::my_typeinfo* data_;
  73. public:
  74. typedef detail::my_typeinfo type_info_t;
  75. inline my_type_index() BOOST_NOEXCEPT
  76. : data_(&detail::my_typeinfo_construct<void>())
  77. {}
  78. inline my_type_index(const type_info_t& data) BOOST_NOEXCEPT
  79. : data_(&data)
  80. {}
  81. inline const type_info_t& type_info() const BOOST_NOEXCEPT {
  82. return *data_;
  83. }
  84. inline const char* raw_name() const BOOST_NOEXCEPT {
  85. return data_->type_;
  86. }
  87. inline std::string pretty_name() const {
  88. return data_->type_;
  89. }
  90. template <class T>
  91. inline static my_type_index type_id() BOOST_NOEXCEPT {
  92. return detail::my_typeinfo_construct<T>();
  93. }
  94. template <class T>
  95. inline static my_type_index type_id_with_cvr() BOOST_NOEXCEPT {
  96. return detail::my_typeinfo_construct<T>();
  97. }
  98. template <class T>
  99. inline static my_type_index type_id_runtime(const T& variable) BOOST_NOEXCEPT;
  100. };
  101. } // namespace my_namespace
  102. /*`
  103. Note that we have used the boost::typeindex::type_index_facade class as base.
  104. That class took care about all the helper function and operators (comparison, hashing, ostreaming and others).
  105. */
  106. //] [/type_index_my_type_index]
  107. //[type_index_my_type_index_register_class
  108. /*`
  109. Usually to allow runtime type info we need to register class with some macro.
  110. Let's see how a `MY_TYPEINDEX_REGISTER_CLASS` macro could be implemented for our `my_type_index` class:
  111. */
  112. namespace my_namespace { namespace detail {
  113. template <class T>
  114. inline const my_typeinfo& my_typeinfo_construct_ref(const T*) {
  115. return my_typeinfo_construct<T>();
  116. }
  117. #define MY_TYPEINDEX_REGISTER_CLASS \
  118. virtual const my_namespace::detail::my_typeinfo& type_id_runtime() const { \
  119. return my_namespace::detail::my_typeinfo_construct_ref(this); \
  120. }
  121. }} // namespace my_namespace::detail
  122. //] [/type_index_my_type_index_register_class]
  123. //[type_index_my_type_index_type_id_runtime_implmentation
  124. /*`
  125. Now when we have a MY_TYPEINDEX_REGISTER_CLASS, let's implement a `my_type_index::type_id_runtime` method:
  126. */
  127. namespace my_namespace {
  128. template <class T>
  129. my_type_index my_type_index::type_id_runtime(const T& variable) BOOST_NOEXCEPT {
  130. // Classes that were marked with `MY_TYPEINDEX_REGISTER_CLASS` will have a
  131. // `type_id_runtime()` method.
  132. return variable.type_id_runtime();
  133. }
  134. }
  135. //] [/type_index_my_type_index_type_id_runtime_implmentation]
  136. //[type_index_my_type_index_type_id_runtime_classes
  137. /*`
  138. Consider the situation, when `my_class` and `my_struct` are polymorphic classes:
  139. */
  140. namespace my_namespace {
  141. class my_class {
  142. public:
  143. MY_TYPEINDEX_REGISTER_CLASS
  144. virtual ~my_class() {}
  145. };
  146. struct my_struct: public my_class {
  147. MY_TYPEINDEX_REGISTER_CLASS
  148. };
  149. } // namespace my_namespace
  150. //] [/type_index_my_type_index_type_id_runtime_classes]
  151. //[type_index_my_type_index_worldwide_typedefs
  152. /*`
  153. You'll also need to add some typedefs and macro to your "user_defined_typeinfo.hpp" header file:
  154. */
  155. #define BOOST_TYPE_INDEX_REGISTER_CLASS MY_TYPEINDEX_REGISTER_CLASS
  156. namespace boost { namespace typeindex {
  157. typedef my_namespace::my_type_index type_index;
  158. }}
  159. //] [/type_index_my_type_index_worldwide_typedefs]
  160. #endif // USER_DEFINED_TYPEINFO_HPP