123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- // Copyright 2013-2019 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}; };
- #ifdef BOOST_MSVC
- #pragma warning(push)
- #pragma warning(disable: 4510 4512 4610) // non-copyable non-constructable type
- #endif
- // my_typeinfo structure is used to save type number
- struct my_typeinfo {
- const char* const type_;
- };
- #ifdef BOOST_MSVC
- #pragma warning(pop)
- #endif
- 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.
- */
- /*`
- Since we are not going to override `type_index_facade::hash_code()` we must additionally include
- `<boost/container_hash/hash.hpp>`.
- */
- #include <boost/container_hash/hash.hpp>
- /*`
- 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
|