forked from boostorg/type_index
Merge pull request #13 from cdglove/split_register_and_implement
Add support for using runtime_cast without requiring type_id_runtime.
This commit is contained in:
@ -10,7 +10,8 @@
|
||||
#define BOOST_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP
|
||||
|
||||
/// \file register_runtime_class.hpp
|
||||
/// \brief Contains the macro BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
|
||||
/// \brief Contains the macros BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST and
|
||||
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
|
||||
#include <boost/type_index.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
|
||||
@ -29,6 +30,8 @@ inline type_index runtime_class_construct_type_id(T const*) {
|
||||
|
||||
} // namespace detail
|
||||
|
||||
}} // namespace boost::typeindex
|
||||
|
||||
/// @cond
|
||||
|
||||
#define BOOST_TYPE_INDEX_CHECK_BASE_(r, data, Base) \
|
||||
@ -44,6 +47,11 @@ inline type_index runtime_class_construct_type_id(T const*) {
|
||||
/// boost::typeindex::runtime_cast to accurately convert between dynamic types of instances of
|
||||
/// the current class.
|
||||
///
|
||||
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS also adds support for boost::typeindex::type_id_runtime
|
||||
/// by including BOOST_TYPE_INDEX_REGISTER_CLASS. It is typical that these features are used together,
|
||||
/// but in the event that BOOST_TYPE_INDEX_REGISTER_CLASS is undesirable in the current class,
|
||||
/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST is provided.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct base1 {
|
||||
@ -67,22 +75,64 @@ inline type_index runtime_class_construct_type_id(T const*) {
|
||||
/// ...
|
||||
///
|
||||
/// base1* pb1 = get_object();
|
||||
/// if(derived2* pb2 = boost::typeindex::runtime_cast<derived2*>(pb1))
|
||||
/// { /* ... */ }
|
||||
/// if(derived2* pb2 = boost::typeindex::runtime_cast<derived2*>(pb1)) {
|
||||
/// assert(boost::typeindex::type_id_runtime(*pb1)) == boost::typeindex::type_id<derived2>());
|
||||
/// }
|
||||
/// \endcode
|
||||
///
|
||||
/// \param base_class_seq A Boost.Preprocessor sequence of the current class' direct bases, or
|
||||
/// BOOST_PP_SEQ_NIL if this class has no direct base classes.
|
||||
/// BOOST_TYPE_INDEX_NO_BASE_CLASS if this class has no direct base classes.
|
||||
#define BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(base_class_seq) \
|
||||
BOOST_TYPE_INDEX_REGISTER_CLASS \
|
||||
BOOST_TYPE_INDEX_REGISTER_CLASS \
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base_class_seq)
|
||||
|
||||
/// \def BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST
|
||||
/// \brief Macro used to make a class compatible with boost::typeindex::runtime_cast without including
|
||||
/// support for boost::typeindex::type_id_runtime.
|
||||
///
|
||||
/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST is provided as an alternative to BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
|
||||
/// in the event that support for boost::typeindex::type_id_runtime is undesirable.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct base1 {
|
||||
/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
/// virtual ~base1();
|
||||
/// };
|
||||
///
|
||||
/// struct base2 {
|
||||
/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
/// virtual ~base2();
|
||||
/// };
|
||||
///
|
||||
/// struct derived1 : base1 {
|
||||
/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base1))
|
||||
/// };
|
||||
///
|
||||
/// struct derived2 : base1, base2 {
|
||||
/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base1)(base2))
|
||||
/// };
|
||||
///
|
||||
/// ...
|
||||
///
|
||||
/// base1* pb1 = get_object();
|
||||
/// if(derived2* pb2 = boost::typeindex::runtime_cast<derived2*>(pb1))
|
||||
/// { /* can't call boost::typeindex::type_id_runtime(*pb1) here */ }
|
||||
/// \endcode
|
||||
///
|
||||
/// \param base_class_seq A Boost.Preprocessor sequence of the current class' direct bases, or
|
||||
/// BOOST_TYPE_INDEX_NO_BASE_CLASS if this class has no direct base classes.
|
||||
#define BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base_class_seq) \
|
||||
virtual void const* boost_type_index_find_instance_(boost::typeindex::type_index const& idx) const BOOST_NOEXCEPT { \
|
||||
if(idx == boost::typeindex::detail::runtime_class_construct_type_id(this)) \
|
||||
return this; \
|
||||
BOOST_PP_SEQ_FOR_EACH(BOOST_TYPE_INDEX_CHECK_BASE_, _, base_class_seq) \
|
||||
return NULL; \
|
||||
}
|
||||
}} // namespace boost::typeindex
|
||||
|
||||
/// \def BOOST_TYPE_INDEX_NO_BASE_CLASS
|
||||
/// \brief Instructs BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS and BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST
|
||||
/// that this class has no base classes.
|
||||
#define BOOST_TYPE_INDEX_NO_BASE_CLASS BOOST_PP_SEQ_NIL
|
||||
|
||||
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP
|
||||
|
@ -28,75 +28,83 @@
|
||||
std::string name;
|
||||
|
||||
struct base {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
IMPLEMENT_CLASS(base)
|
||||
};
|
||||
|
||||
struct single_derived : base {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
|
||||
IMPLEMENT_CLASS(single_derived)
|
||||
};
|
||||
|
||||
struct base1 {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
IMPLEMENT_CLASS(base1)
|
||||
};
|
||||
|
||||
struct base2 {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
IMPLEMENT_CLASS(base2)
|
||||
};
|
||||
|
||||
struct multiple_derived : base1, base2 {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base1)(base2))
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base1)(base2))
|
||||
IMPLEMENT_CLASS(multiple_derived)
|
||||
};
|
||||
|
||||
struct baseV1 : virtual base {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
|
||||
IMPLEMENT_CLASS(baseV1)
|
||||
};
|
||||
|
||||
struct baseV2 : virtual base {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
|
||||
IMPLEMENT_CLASS(baseV2)
|
||||
};
|
||||
|
||||
struct multiple_virtual_derived : baseV1, baseV2 {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((baseV1)(baseV2))
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((baseV1)(baseV2))
|
||||
IMPLEMENT_CLASS(multiple_virtual_derived)
|
||||
};
|
||||
|
||||
struct unrelated {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
IMPLEMENT_CLASS(unrelated)
|
||||
};
|
||||
|
||||
struct unrelated_with_base : base {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
|
||||
IMPLEMENT_CLASS(unrelated_with_base)
|
||||
};
|
||||
|
||||
struct unrelatedV1 : virtual base {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
|
||||
IMPLEMENT_CLASS(unrelatedV1)
|
||||
};
|
||||
|
||||
struct level1_a : base {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
|
||||
IMPLEMENT_CLASS(level1_a)
|
||||
};
|
||||
|
||||
struct level1_b : base {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base))
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
|
||||
IMPLEMENT_CLASS(level1_b)
|
||||
};
|
||||
|
||||
struct level2 : level1_a, level1_b {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((level1_a)(level1_b))
|
||||
BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((level1_a)(level1_b))
|
||||
IMPLEMENT_CLASS(level2)
|
||||
};
|
||||
|
||||
struct reg_base {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
};
|
||||
|
||||
struct reg_derived : reg_base {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((reg_base))
|
||||
};
|
||||
|
||||
void no_base()
|
||||
{
|
||||
using namespace boost::typeindex;
|
||||
@ -261,6 +269,16 @@ void std_shared_ptr()
|
||||
#endif
|
||||
}
|
||||
|
||||
void register_runtime_class()
|
||||
{
|
||||
using namespace boost::typeindex;
|
||||
reg_derived rd;
|
||||
reg_base* rb = &rd;
|
||||
reg_derived* prd = runtime_pointer_cast<reg_derived>(rb);
|
||||
BOOST_TEST_NE(prd, (reg_derived*)NULL);
|
||||
BOOST_TEST_EQ(type_id_runtime(*prd), type_id<reg_derived>());
|
||||
}
|
||||
|
||||
int main() {
|
||||
no_base();
|
||||
single_derived();
|
||||
@ -273,5 +291,6 @@ int main() {
|
||||
diamond_non_virtual();
|
||||
boost_shared_ptr();
|
||||
std_shared_ptr();
|
||||
register_runtime_class();
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
Reference in New Issue
Block a user