blob: 5690a00223c261b0b4c823ab1a03ac62b38e2f4a [file] [log] [blame]
// 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