]>
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 | ||
50 | // my_typeinfo structure is used to save type number | |
51 | struct my_typeinfo { | |
52 | const char* const type_; | |
53 | }; | |
54 | ||
55 | const my_typeinfo infos[5] = { | |
56 | {"void"}, {"my_class"}, {"my_struct"}, {"my_classes"}, {"my_string"} | |
57 | }; | |
58 | ||
59 | template <class T> | |
60 | inline const my_typeinfo& my_typeinfo_construct() { | |
61 | return infos[typenum<T>::value]; | |
62 | } | |
63 | }} // my_namespace::detail | |
64 | ||
65 | //] [/type_index_userdefined_usertypes] | |
66 | ||
67 | ||
68 | //[type_index_my_type_index | |
69 | /*` | |
70 | `my_type_index` is a user created type_index class. If in doubt during this phase, you can always | |
71 | take a look at the `<boost/type_index/ctti_type_index.hpp>` or `<boost/type_index/stl_type_index.hpp>` | |
72 | files. Documentation for `type_index_facade` could be also useful. | |
73 | ||
74 | See implementation of `my_type_index`: | |
75 | */ | |
76 | namespace my_namespace { | |
77 | ||
78 | class my_type_index: public boost::typeindex::type_index_facade<my_type_index, detail::my_typeinfo> { | |
79 | const detail::my_typeinfo* data_; | |
80 | ||
81 | public: | |
82 | typedef detail::my_typeinfo type_info_t; | |
83 | ||
84 | inline my_type_index() BOOST_NOEXCEPT | |
85 | : data_(&detail::my_typeinfo_construct<void>()) | |
86 | {} | |
87 | ||
88 | inline my_type_index(const type_info_t& data) BOOST_NOEXCEPT | |
89 | : data_(&data) | |
90 | {} | |
91 | ||
92 | inline const type_info_t& type_info() const BOOST_NOEXCEPT { | |
93 | return *data_; | |
94 | } | |
95 | ||
96 | inline const char* raw_name() const BOOST_NOEXCEPT { | |
97 | return data_->type_; | |
98 | } | |
99 | ||
100 | inline std::string pretty_name() const { | |
101 | return data_->type_; | |
102 | } | |
103 | ||
104 | template <class T> | |
105 | inline static my_type_index type_id() BOOST_NOEXCEPT { | |
106 | return detail::my_typeinfo_construct<T>(); | |
107 | } | |
108 | ||
109 | template <class T> | |
110 | inline static my_type_index type_id_with_cvr() BOOST_NOEXCEPT { | |
111 | return detail::my_typeinfo_construct<T>(); | |
112 | } | |
113 | ||
114 | template <class T> | |
115 | inline static my_type_index type_id_runtime(const T& variable) BOOST_NOEXCEPT; | |
116 | }; | |
117 | ||
118 | } // namespace my_namespace | |
119 | ||
120 | /*` | |
121 | Note that we have used the boost::typeindex::type_index_facade class as base. | |
122 | That class took care about all the helper function and operators (comparison, hashing, ostreaming and others). | |
123 | */ | |
124 | ||
125 | //] [/type_index_my_type_index] | |
126 | ||
127 | //[type_index_my_type_index_register_class | |
128 | /*` | |
129 | Usually to allow runtime type info we need to register class with some macro. | |
130 | Let's see how a `MY_TYPEINDEX_REGISTER_CLASS` macro could be implemented for our `my_type_index` class: | |
131 | */ | |
132 | namespace my_namespace { namespace detail { | |
133 | ||
134 | template <class T> | |
135 | inline const my_typeinfo& my_typeinfo_construct_ref(const T*) { | |
136 | return my_typeinfo_construct<T>(); | |
137 | } | |
138 | ||
139 | #define MY_TYPEINDEX_REGISTER_CLASS \ | |
140 | virtual const my_namespace::detail::my_typeinfo& type_id_runtime() const { \ | |
141 | return my_namespace::detail::my_typeinfo_construct_ref(this); \ | |
142 | } | |
143 | ||
144 | }} // namespace my_namespace::detail | |
145 | ||
146 | //] [/type_index_my_type_index_register_class] | |
147 | ||
148 | //[type_index_my_type_index_type_id_runtime_implmentation | |
149 | /*` | |
150 | Now when we have a MY_TYPEINDEX_REGISTER_CLASS, let's implement a `my_type_index::type_id_runtime` method: | |
151 | */ | |
152 | namespace my_namespace { | |
153 | template <class T> | |
154 | my_type_index my_type_index::type_id_runtime(const T& variable) BOOST_NOEXCEPT { | |
155 | // Classes that were marked with `MY_TYPEINDEX_REGISTER_CLASS` will have a | |
156 | // `type_id_runtime()` method. | |
157 | return variable.type_id_runtime(); | |
158 | } | |
159 | } | |
160 | //] [/type_index_my_type_index_type_id_runtime_implmentation] | |
161 | ||
162 | //[type_index_my_type_index_type_id_runtime_classes | |
163 | /*` | |
164 | Consider the situation, when `my_class` and `my_struct` are polymorphic classes: | |
165 | */ | |
166 | ||
167 | namespace my_namespace { | |
168 | ||
169 | class my_class { | |
170 | public: | |
171 | MY_TYPEINDEX_REGISTER_CLASS | |
172 | virtual ~my_class() {} | |
173 | }; | |
174 | ||
175 | struct my_struct: public my_class { | |
176 | MY_TYPEINDEX_REGISTER_CLASS | |
177 | }; | |
178 | ||
179 | } // namespace my_namespace | |
180 | ||
181 | //] [/type_index_my_type_index_type_id_runtime_classes] | |
182 | ||
183 | ||
184 | //[type_index_my_type_index_worldwide_typedefs | |
185 | /*` | |
186 | You'll also need to add some typedefs and macro to your "user_defined_typeinfo.hpp" header file: | |
187 | */ | |
188 | #define BOOST_TYPE_INDEX_REGISTER_CLASS MY_TYPEINDEX_REGISTER_CLASS | |
189 | namespace boost { namespace typeindex { | |
190 | typedef my_namespace::my_type_index type_index; | |
191 | }} | |
192 | //] [/type_index_my_type_index_worldwide_typedefs] | |
193 | ||
194 | ||
195 | #endif // USER_DEFINED_TYPEINFO_HPP | |
196 |