From d8bdbad2ec00ae8b1db4d155cd3403abe068a354 Mon Sep 17 00:00:00 2001 From: Chris Glover Date: Sat, 5 Nov 2016 16:04:13 -0400 Subject: [PATCH 1/2] Add BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST, which implementes the functionality for runtime_cast to function, but does not include the BOOST_TYPE_INDEX_REGISTER_CLASS macro. Reimplement BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS to simply call BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST and BOOST_TYPE_INDEX_REGISTER_CLASS. This allows users to opt-in to one or the other, instead of forcing them to generate both virtual functions. --- .../runtime_cast/register_runtime_class.hpp | 62 +++++++++++++++++-- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/include/boost/type_index/runtime_cast/register_runtime_class.hpp b/include/boost/type_index/runtime_cast/register_runtime_class.hpp index 37ce686..9950074 100644 --- a/include/boost/type_index/runtime_cast/register_runtime_class.hpp +++ b/include/boost/type_index/runtime_cast/register_runtime_class.hpp @@ -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 #include @@ -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(pb1)) -/// { /* ... */ } +/// if(derived2* pb2 = boost::typeindex::runtime_cast(pb1)) { +/// assert(boost::typeindex::type_id_runtime(*pb1)) == boost::typeindex::type_id()); +/// } /// \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(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 From d3d4e8d18a32a9ae5ac6ade3c0a5d9d4abbe7c62 Mon Sep 17 00:00:00 2001 From: Chris Glover Date: Sat, 25 Feb 2017 15:30:11 -0500 Subject: [PATCH 2/2] Change runtime cast test to use the separated macro (BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST) and add a new test that ensures BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS does indeed supply both functions. --- test/type_index_runtime_cast_test.cpp | 47 +++++++++++++++++++-------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/test/type_index_runtime_cast_test.cpp b/test/type_index_runtime_cast_test.cpp index cd24bb3..1f5344e 100644 --- a/test/type_index_runtime_cast_test.cpp +++ b/test/type_index_runtime_cast_test.cpp @@ -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(rb); + BOOST_TEST_NE(prd, (reg_derived*)NULL); + BOOST_TEST_EQ(type_id_runtime(*prd), type_id()); +} + 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(); }