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
9#ifndef BOOST_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP
10#define BOOST_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP
11
12/// \file register_runtime_class.hpp
13/// \brief Contains the macros BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST and
14/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
15#include <boost/type_index.hpp>
16
17#ifdef BOOST_HAS_PRAGMA_ONCE
18# pragma once
19#endif
20
21namespace boost { namespace typeindex { namespace detail {
22
23template<typename T>
24inline type_index runtime_class_construct_type_id(T const*) {
25 return boost::typeindex::type_id<T>();
26}
27
28template <class Self>
29constexpr const void* find_instance(boost::typeindex::type_index const&, const Self*) noexcept {
30 return nullptr;
31}
32
33template <class Base, class... OtherBases, class Self>
34const void* find_instance(boost::typeindex::type_index const& idx, const Self* self) noexcept {
35 if (const void* ptr = self->Base::boost_type_index_find_instance_(idx)) {
36 return ptr;
37 }
38
39 return boost::typeindex::detail::find_instance<OtherBases...>(idx, self);
40}
41
42}}} // namespace boost::typeindex::detail
43
44
45/// \def BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
46/// \brief Macro used to make a class compatible with boost::typeindex::runtime_cast
47///
48/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS generates a virtual function
49/// in the current class that, when combined with the supplied base class information, allows
50/// boost::typeindex::runtime_cast to accurately convert between dynamic types of instances of
51/// the current class.
52///
53/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS also adds support for boost::typeindex::type_id_runtime
54/// by including BOOST_TYPE_INDEX_REGISTER_CLASS. It is typical that these features are used together,
55/// but in the event that BOOST_TYPE_INDEX_REGISTER_CLASS is undesirable in the current class,
56/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST is provided.
57///
58/// \b Example:
59/// \code
60/// struct base1 {
61/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS()
62/// virtual ~base1();
63/// };
64///
65/// struct base2 {
66/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS()
67/// virtual ~base2();
68/// };
69///
70/// struct derived1 : base1 {
71/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(base1)
72/// };
73///
74/// struct derived2 : base1, base2 {
75/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(base1, base2)
76/// };
77///
78/// ...
79///
80/// base1* pb1 = get_object();
81/// if(derived2* pb2 = boost::typeindex::runtime_cast<derived2*>(pb1)) {
82/// assert(boost::typeindex::type_id_runtime(*pb1)) == boost::typeindex::type_id<derived2>());
83/// }
84/// \endcode
85///
86/// \param base_class_seq A Boost.Preprocessor sequence of the current class' direct bases, or
87/// BOOST_TYPE_INDEX_NO_BASE_CLASS if this class has no direct base classes.
88#define BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(...) \
89 BOOST_TYPE_INDEX_REGISTER_CLASS \
90 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(__VA_ARGS__)
91
92/// \def BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST
93/// \brief Macro used to make a class compatible with boost::typeindex::runtime_cast without including
94/// support for boost::typeindex::type_id_runtime.
95///
96/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST is provided as an alternative to BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
97/// in the event that support for boost::typeindex::type_id_runtime is undesirable.
98///
99/// \b Example:
100/// \code
101/// struct base1 {
102/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST()
103/// virtual ~base1();
104/// };
105///
106/// struct base2 {
107/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST()
108/// virtual ~base2();
109/// };
110///
111/// struct derived1 : base1 {
112/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base1)
113/// };
114///
115/// struct derived2 : base1, base2 {
116/// BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base1, base2)
117/// };
118///
119/// ...
120///
121/// base1* pb1 = get_object();
122/// if(derived2* pb2 = boost::typeindex::runtime_cast<derived2*>(pb1))
123/// { /* can't call boost::typeindex::type_id_runtime(*pb1) here */ }
124/// \endcode
125///
126/// \param base_class_seq A Boost.Preprocessor sequence of the current class' direct bases, or
127/// BOOST_TYPE_INDEX_NO_BASE_CLASS if this class has no direct base classes.
128#define BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(...) \
129 virtual void const* boost_type_index_find_instance_(boost::typeindex::type_index const& idx) const noexcept { \
130 if(idx == boost::typeindex::detail::runtime_class_construct_type_id(this)) \
131 return this; \
132 return boost::typeindex::detail::find_instance<__VA_ARGS__>(idx, this); \
133 }
134
135/// \def BOOST_TYPE_INDEX_NO_BASE_CLASS
136/// \brief Instructs BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS and BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST
137/// that this class has no base classes.
138/// \deprecated Just remove and use BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS() or BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST()
139#define BOOST_TYPE_INDEX_NO_BASE_CLASS /**/
140
141#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP
142

source code of boost/libs/type_index/include/boost/type_index/runtime_cast/register_runtime_class.hpp