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