register_runtime_class.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. //
  2. // Copyright (c) Chris Glover, 2016.
  3. //
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. #ifndef BOOST_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP
  9. #define BOOST_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP
  10. /// \file register_runtime_class.hpp
  11. /// \brief Contains the macros BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST and
  12. /// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
  13. #include <boost/type_index.hpp>
  14. #include <boost/preprocessor/seq/for_each.hpp>
  15. #ifdef BOOST_HAS_PRAGMA_ONCE
  16. # pragma once
  17. #endif
  18. namespace boost { namespace typeindex {
  19. namespace detail {
  20. template<typename T>
  21. inline type_index runtime_class_construct_type_id(T const*) {
  22. return type_id<T>();
  23. }
  24. } // namespace detail
  25. }} // namespace boost::typeindex
  26. /// @cond
  27. #define BOOST_TYPE_INDEX_CHECK_BASE_(r, data, Base) \
  28. if(void const* ret_val = this->Base::boost_type_index_find_instance_(idx)) return ret_val;
  29. /// @endcond
  30. /// \def BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
  31. /// \brief Macro used to make a class compatible with boost::typeindex::runtime_cast
  32. ///
  33. /// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS generates a virtual function
  34. /// in the current class that, when combined with the supplied base class information, allows
  35. /// boost::typeindex::runtime_cast to accurately convert between dynamic types of instances of
  36. /// the current class.
  37. ///
  38. /// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS also adds support for boost::typeindex::type_id_runtime
  39. /// by including BOOST_TYPE_INDEX_REGISTER_CLASS. It is typical that these features are used together,
  40. /// but in the event that BOOST_TYPE_INDEX_REGISTER_CLASS is undesirable in the current class,
  41. /// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST is provided.
  42. ///
  43. /// \b Example:
  44. /// \code
  45. /// struct base1 {
  46. /// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
  47. /// virtual ~base1();
  48. /// };
  49. ///
  50. /// struct base2 {
  51. /// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
  52. /// virtual ~base2();
  53. /// };
  54. ///
  55. /// struct derived1 : base1 {
  56. /// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base1))
  57. /// };
  58. ///
  59. /// struct derived2 : base1, base2 {
  60. /// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base1)(base2))
  61. /// };
  62. ///
  63. /// ...
  64. ///
  65. /// base1* pb1 = get_object();
  66. /// if(derived2* pb2 = boost::typeindex::runtime_cast<derived2*>(pb1)) {
  67. /// assert(boost::typeindex::type_id_runtime(*pb1)) == boost::typeindex::type_id<derived2>());
  68. /// }
  69. /// \endcode
  70. ///
  71. /// \param base_class_seq A Boost.Preprocessor sequence of the current class' direct bases, or
  72. /// BOOST_TYPE_INDEX_NO_BASE_CLASS if this class has no direct base classes.
  73. #define BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(base_class_seq) \
  74. BOOST_TYPE_INDEX_REGISTER_CLASS \
  75. BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base_class_seq)
  76. /// \def BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST
  77. /// \brief Macro used to make a class compatible with boost::typeindex::runtime_cast without including
  78. /// support for boost::typeindex::type_id_runtime.
  79. ///
  80. /// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST is provided as an alternative to BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
  81. /// in the event that support for boost::typeindex::type_id_runtime is undesirable.
  82. ///
  83. /// \b Example:
  84. /// \code
  85. /// struct base1 {
  86. /// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
  87. /// virtual ~base1();
  88. /// };
  89. ///
  90. /// struct base2 {
  91. /// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
  92. /// virtual ~base2();
  93. /// };
  94. ///
  95. /// struct derived1 : base1 {
  96. /// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base1))
  97. /// };
  98. ///
  99. /// struct derived2 : base1, base2 {
  100. /// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base1)(base2))
  101. /// };
  102. ///
  103. /// ...
  104. ///
  105. /// base1* pb1 = get_object();
  106. /// if(derived2* pb2 = boost::typeindex::runtime_cast<derived2*>(pb1))
  107. /// { /* can't call boost::typeindex::type_id_runtime(*pb1) here */ }
  108. /// \endcode
  109. ///
  110. /// \param base_class_seq A Boost.Preprocessor sequence of the current class' direct bases, or
  111. /// BOOST_TYPE_INDEX_NO_BASE_CLASS if this class has no direct base classes.
  112. #define BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base_class_seq) \
  113. virtual void const* boost_type_index_find_instance_(boost::typeindex::type_index const& idx) const BOOST_NOEXCEPT { \
  114. if(idx == boost::typeindex::detail::runtime_class_construct_type_id(this)) \
  115. return this; \
  116. BOOST_PP_SEQ_FOR_EACH(BOOST_TYPE_INDEX_CHECK_BASE_, _, base_class_seq) \
  117. return NULL; \
  118. }
  119. /// \def BOOST_TYPE_INDEX_NO_BASE_CLASS
  120. /// \brief Instructs BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS and BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST
  121. /// that this class has no base classes.
  122. #define BOOST_TYPE_INDEX_NO_BASE_CLASS BOOST_PP_SEQ_NIL
  123. #endif // BOOST_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP