mirror of
https://github.com/boostorg/type_index.git
synced 2025-07-29 20:07:18 +02:00
Finished example with user defined type_index, improved doocs and refactored some of the functions
This commit is contained in:
@ -203,13 +203,34 @@ expands to nothing.
|
||||
[xinclude autodoc.xml]
|
||||
|
||||
[section Making own type_index]
|
||||
|
||||
Sometimes there may be a need to create your own type info system. This may be usefull if you wish to store some more info about types (PODness, size of a type, pointers to common functions...) or if you have an idea of a more compact types representations.
|
||||
|
||||
[import ../examples/user_defined_typeinfo.hpp]
|
||||
[import ../examples/user_defined_typeinfo.cpp]
|
||||
|
||||
[section Basics]
|
||||
[type_index_userdefined_usertypes]
|
||||
[type_index_userdefined_enum]
|
||||
[type_index_my_type_index]
|
||||
[type_index_my_type_index_usage]
|
||||
[endsect]
|
||||
|
||||
[section Getting type infos at runtime]
|
||||
[type_index_my_type_index_register_class]
|
||||
[type_index_my_type_index_type_id_runtime_implmentation]
|
||||
[type_index_my_type_index_type_id_runtime_classes]
|
||||
[type_index_my_type_index_type_id_runtime_test]
|
||||
[endsect]
|
||||
|
||||
[section Using new type infos all around the code]
|
||||
[type_index_my_type_index_worldwide_macro]
|
||||
[type_index_my_type_index_worldwide_typedefs]
|
||||
[type_index_my_type_index_worldwide_usage]
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Space and Performance]
|
||||
|
||||
|
@ -4,136 +4,31 @@
|
||||
// (See the accompanying file LICENSE_1_0.txt
|
||||
// or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
|
||||
|
||||
//[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()`:
|
||||
//[type_index_my_type_index_worldwide_macro
|
||||
/*`
|
||||
There is an easy way to force `boost::typeind::type_id` to use your own type_index class.
|
||||
|
||||
All we need to do is just define `BOOST_TYPE_INDEX_USER_TYPEINDEX` to the full path to header file
|
||||
of your type index class:
|
||||
*/
|
||||
|
||||
#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]
|
||||
// BOOST_TYPE_INDEX_USER_TYPEINDEX must be defined *BEFORE* first inclusion of <boost/type_index.hpp>
|
||||
#define BOOST_TYPE_INDEX_USER_TYPEINDEX <boost/../libs/type_index/examples/user_defined_typeinfo.hpp>
|
||||
#include <boost/type_index.hpp>
|
||||
//] [/type_index_my_type_index_worldwide_macro]
|
||||
|
||||
|
||||
//[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 {
|
||||
// type_[0] will hold a type number
|
||||
// type_[1] will be '\0', to have a zero terminated raw type name
|
||||
char type_[2];
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const my_typeinfo& my_typeinfo_construct() {
|
||||
static const my_typeinfo ret = {{ static_cast<char>(typenum<T>::value), '\0' }};
|
||||
return ret;
|
||||
}
|
||||
}} // 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::typeind::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 {
|
||||
// Must be in sync with detail::typenum<T>::value
|
||||
static const char* names[] = {
|
||||
"void", "my_class", "my_struct", "my_classes", "my_string"
|
||||
};
|
||||
|
||||
const std::size_t indx = static_cast<std::size_t>(data_->type_[0]);
|
||||
return names[indx];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline static my_type_index type_id() BOOST_NOEXCEPT {
|
||||
return detail::my_typeinfo_construct<T>();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace my_namespace
|
||||
|
||||
/*`
|
||||
Note that we have used the boost::typeind::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]
|
||||
|
||||
namespace my_namespace {
|
||||
|
||||
class my_class{};
|
||||
struct my_struct{};
|
||||
|
||||
} // namespace my_namespace
|
||||
|
||||
//[type_index_my_type_index_usage
|
||||
/*`
|
||||
Finally we can use the my_type_index class for getting type indexes:
|
||||
*/
|
||||
|
||||
using namespace my_namespace;
|
||||
#include <cassert>
|
||||
|
||||
int main() {
|
||||
//[type_index_my_type_index_usage
|
||||
/*`
|
||||
Finally we can use the my_type_index class for getting type indexes:
|
||||
*/
|
||||
|
||||
my_type_index
|
||||
cl1 = my_type_index::type_id<my_class>(),
|
||||
st1 = my_type_index::type_id<my_struct>(),
|
||||
@ -145,7 +40,26 @@ int main() {
|
||||
assert(st2 == st1);
|
||||
assert(vec.pretty_name() == "my_classes");
|
||||
assert(cl1.pretty_name() == "my_class");
|
||||
}
|
||||
|
||||
//] [/type_index_my_type_index_usage]
|
||||
|
||||
//[type_index_my_type_index_type_id_runtime_test
|
||||
/*`
|
||||
Now the follwoing example will compile and work.
|
||||
*/
|
||||
my_struct str;
|
||||
my_class& reference = str;
|
||||
assert(my_type_index::type_id<my_struct>() == my_type_index::type_id_runtime(reference));
|
||||
//][/type_index_my_type_index_type_id_runtime_test]
|
||||
|
||||
//[type_index_my_type_index_worldwide_usage
|
||||
/*`
|
||||
That's it! Now all TypeIndex global methods and typedefs will be using your class:
|
||||
*/
|
||||
boost::typeind::type_index worldwide = boost::typeind::type_id<my_classes>();
|
||||
assert(worldwide.pretty_name() == "my_classes");
|
||||
assert(worldwide == my_type_index::type_id<my_classes>());
|
||||
//][/type_index_my_type_index_worldwide_usage]
|
||||
}
|
||||
|
||||
|
||||
|
201
examples/user_defined_typeinfo.hpp
Normal file
201
examples/user_defined_typeinfo.hpp
Normal file
@ -0,0 +1,201 @@
|
||||
// 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 {
|
||||
// type_[0] will hold a type number
|
||||
// type_[1] will be '\0', to have a zero terminated raw type name
|
||||
char type_[2];
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const my_typeinfo& my_typeinfo_construct() {
|
||||
static const my_typeinfo ret = {{ static_cast<char>(typenum<T>::value), '\0' }};
|
||||
return ret;
|
||||
}
|
||||
}} // 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::typeind::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 {
|
||||
// Must be in sync with detail::typenum<T>::value
|
||||
static const char* names[] = {
|
||||
"void", "my_class", "my_struct", "my_classes", "my_string"
|
||||
};
|
||||
|
||||
const std::size_t indx = static_cast<std::size_t>(data_->type_[0]);
|
||||
return names[indx];
|
||||
}
|
||||
|
||||
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::typeind::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 typeind {
|
||||
typedef my_namespace::my_type_index type_index;
|
||||
}}
|
||||
//] [/type_index_my_type_index_worldwide_typedefs]
|
||||
|
||||
|
||||
#endif // USER_DEFINED_TYPEINFO_HPP
|
||||
|
@ -67,6 +67,10 @@ typedef type_index::type_info_t type_info;
|
||||
/// \def BOOST_TYPE_INDEX_REGISTER_CLASS
|
||||
/// BOOST_TYPE_INDEX_REGISTER_CLASS is a helper macro that is used to help to emulate RTTI.
|
||||
/// Put this macro into the public section of polymorphic class to allow runtime type detection.
|
||||
///
|
||||
/// Depending on the typeid() availability this macro will expand to nothing or to virtual helper function
|
||||
/// `virtual const type_info& type_id_runtime() const`.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// class A {
|
||||
|
@ -29,10 +29,10 @@ inline const ctti_data& ctti_construct_typeid_ref(const T*) BOOST_NOEXCEPT {
|
||||
}}} // namespace boost::typeind::detail
|
||||
|
||||
|
||||
#define BOOST_TYPE_INDEX_REGISTER_CTTI_CLASS \
|
||||
virtual const boost::typeind::detail::ctti_data& type_id_ref() const BOOST_NOEXCEPT { \
|
||||
return boost::typeind::detail::ctti_construct_typeid_ref(this); \
|
||||
} \
|
||||
#define BOOST_TYPE_INDEX_REGISTER_CTTI_CLASS \
|
||||
virtual const boost::typeind::detail::ctti_data& type_id_runtime() const BOOST_NOEXCEPT { \
|
||||
return boost::typeind::detail::ctti_construct_typeid_ref(this); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
#endif // BOOST_TYPE_INDEX_CTTI_REGISTER_CLASS_HPP
|
||||
|
@ -101,7 +101,7 @@ inline ctti_type_index ctti_type_index::type_id_with_cvr() BOOST_NOEXCEPT {
|
||||
|
||||
template <class T>
|
||||
inline ctti_type_index ctti_type_index::type_id_runtime(const T& variable) BOOST_NOEXCEPT {
|
||||
return variable.type_id_ref();
|
||||
return variable.type_id_runtime();
|
||||
}
|
||||
|
||||
|
||||
|
@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(comparators_type_id_runtime)
|
||||
BOOST_CHECK(typeid(&rc1) == typeid(pb1));
|
||||
BOOST_CHECK(typeid(&rb1) == typeid(pc1));
|
||||
#else
|
||||
BOOST_CHECK(boost::typeind::type_index(pc1->type_id_ref()).raw_name());
|
||||
BOOST_CHECK(boost::typeind::type_index(pc1->type_id_runtime()).raw_name());
|
||||
#endif
|
||||
|
||||
BOOST_CHECK_EQUAL(boost::typeind::type_id_runtime(rc1), boost::typeind::type_id_runtime(*pc1));
|
||||
|
Reference in New Issue
Block a user