| // Copyright 2013-2014 Antony Polukhin |
| |
| // Distributed under the Boost Software License, Version 1.0. |
| // (See the accompanying file LICENSE_1_0.txt |
| // or a copy at <http://www.boost.org/LICENSE_1_0.txt>.) |
| |
| #ifndef USER_DEFINED_TYPEINFO_HPP |
| #define USER_DEFINED_TYPEINFO_HPP |
| |
| //[type_index_userdefined_usertypes |
| /*` |
| The following example shows how a user defined type_info can be created and used. |
| Example works with and without RTTI. |
| |
| Consider situation when user uses only those types in `typeid()`: |
| */ |
| |
| #include <vector> |
| #include <string> |
| |
| namespace my_namespace { |
| |
| class my_class; |
| struct my_struct; |
| |
| typedef std::vector<my_class> my_classes; |
| typedef std::string my_string; |
| |
| } // namespace my_namespace |
| |
| //] [/type_index_userdefined_usertypes] |
| |
| |
| //[type_index_userdefined_enum |
| /*` |
| In that case user may wish to save space in binary and create it's own type system. |
| For that case `detail::typenum<>` meta function is added. Depending on the input type T |
| this function will return different numeric values. |
| */ |
| #include <boost/type_index/type_index_facade.hpp> |
| |
| namespace my_namespace { namespace detail { |
| template <class T> struct typenum; |
| template <> struct typenum<void>{ enum {value = 0}; }; |
| template <> struct typenum<my_class>{ enum {value = 1}; }; |
| template <> struct typenum<my_struct>{ enum {value = 2}; }; |
| template <> struct typenum<my_classes>{ enum {value = 3}; }; |
| template <> struct typenum<my_string>{ enum {value = 4}; }; |
| |
| // my_typeinfo structure is used to save type number |
| struct my_typeinfo { |
| const char* const type_; |
| }; |
| |
| const my_typeinfo infos[5] = { |
| {"void"}, {"my_class"}, {"my_struct"}, {"my_classes"}, {"my_string"} |
| }; |
| |
| template <class T> |
| inline const my_typeinfo& my_typeinfo_construct() { |
| return infos[typenum<T>::value]; |
| } |
| }} // my_namespace::detail |
| |
| //] [/type_index_userdefined_usertypes] |
| |
| |
| //[type_index_my_type_index |
| /*` |
| `my_type_index` is a user created type_index class. If in doubt during this phase, you can always |
| take a look at the `<boost/type_index/ctti_type_index.hpp>` or `<boost/type_index/stl_type_index.hpp>` |
| files. Documentation for `type_index_facade` could be also useful. |
| |
| See implementation of `my_type_index`: |
| */ |
| namespace my_namespace { |
| |
| class my_type_index: public boost::typeindex::type_index_facade<my_type_index, detail::my_typeinfo> { |
| const detail::my_typeinfo* data_; |
| |
| public: |
| typedef detail::my_typeinfo type_info_t; |
| |
| inline my_type_index() BOOST_NOEXCEPT |
| : data_(&detail::my_typeinfo_construct<void>()) |
| {} |
| |
| inline my_type_index(const type_info_t& data) BOOST_NOEXCEPT |
| : data_(&data) |
| {} |
| |
| inline const type_info_t& type_info() const BOOST_NOEXCEPT { |
| return *data_; |
| } |
| |
| inline const char* raw_name() const BOOST_NOEXCEPT { |
| return data_->type_; |
| } |
| |
| inline std::string pretty_name() const { |
| return data_->type_; |
| } |
| |
| template <class T> |
| inline static my_type_index type_id() BOOST_NOEXCEPT { |
| return detail::my_typeinfo_construct<T>(); |
| } |
| |
| template <class T> |
| inline static my_type_index type_id_with_cvr() BOOST_NOEXCEPT { |
| return detail::my_typeinfo_construct<T>(); |
| } |
| |
| template <class T> |
| inline static my_type_index type_id_runtime(const T& variable) BOOST_NOEXCEPT; |
| }; |
| |
| } // namespace my_namespace |
| |
| /*` |
| Note that we have used the boost::typeindex::type_index_facade class as base. |
| That class took care about all the helper function and operators (comparison, hashing, ostreaming and others). |
| */ |
| |
| //] [/type_index_my_type_index] |
| |
| //[type_index_my_type_index_register_class |
| /*` |
| Usually to allow runtime type info we need to register class with some macro. |
| Let's see how a `MY_TYPEINDEX_REGISTER_CLASS` macro could be implemented for our `my_type_index` class: |
| */ |
| namespace my_namespace { namespace detail { |
| |
| template <class T> |
| inline const my_typeinfo& my_typeinfo_construct_ref(const T*) { |
| return my_typeinfo_construct<T>(); |
| } |
| |
| #define MY_TYPEINDEX_REGISTER_CLASS \ |
| virtual const my_namespace::detail::my_typeinfo& type_id_runtime() const { \ |
| return my_namespace::detail::my_typeinfo_construct_ref(this); \ |
| } |
| |
| }} // namespace my_namespace::detail |
| |
| //] [/type_index_my_type_index_register_class] |
| |
| //[type_index_my_type_index_type_id_runtime_implmentation |
| /*` |
| Now when we have a MY_TYPEINDEX_REGISTER_CLASS, let's implement a `my_type_index::type_id_runtime` method: |
| */ |
| namespace my_namespace { |
| template <class T> |
| my_type_index my_type_index::type_id_runtime(const T& variable) BOOST_NOEXCEPT { |
| // Classes that were marked with `MY_TYPEINDEX_REGISTER_CLASS` will have a |
| // `type_id_runtime()` method. |
| return variable.type_id_runtime(); |
| } |
| } |
| //] [/type_index_my_type_index_type_id_runtime_implmentation] |
| |
| //[type_index_my_type_index_type_id_runtime_classes |
| /*` |
| Consider the situation, when `my_class` and `my_struct` are polymorphic classes: |
| */ |
| |
| namespace my_namespace { |
| |
| class my_class { |
| public: |
| MY_TYPEINDEX_REGISTER_CLASS |
| virtual ~my_class() {} |
| }; |
| |
| struct my_struct: public my_class { |
| MY_TYPEINDEX_REGISTER_CLASS |
| }; |
| |
| } // namespace my_namespace |
| |
| //] [/type_index_my_type_index_type_id_runtime_classes] |
| |
| |
| //[type_index_my_type_index_worldwide_typedefs |
| /*` |
| You'll also need to add some typedefs and macro to your "user_defined_typeinfo.hpp" header file: |
| */ |
| #define BOOST_TYPE_INDEX_REGISTER_CLASS MY_TYPEINDEX_REGISTER_CLASS |
| namespace boost { namespace typeindex { |
| typedef my_namespace::my_type_index type_index; |
| }} |
| //] [/type_index_my_type_index_worldwide_typedefs] |
| |
| |
| #endif // USER_DEFINED_TYPEINFO_HPP |
| |