mirror of
https://github.com/boostorg/type_index.git
synced 2025-07-29 20:07:18 +02:00
Initial documentation.
This commit is contained in:
@ -11,6 +11,7 @@ doxygen autodoc
|
||||
:
|
||||
[ glob ../../../boost/type_index.hpp ]
|
||||
[ glob ../../../boost/type_index/*.hpp ]
|
||||
[ glob ../../../boost/type_index/runtime_cast/*.hpp ]
|
||||
:
|
||||
<doxygen:param>EXTRACT_ALL=NO
|
||||
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
|
||||
|
@ -246,6 +246,10 @@ Depending on the `typeid()` availability TypeIndex library will choose an optima
|
||||
[macroref BOOST_TYPE_INDEX_REGISTER_CLASS] macro is a helper macro that places some virtual helper functions or
|
||||
expands to nothing.
|
||||
|
||||
[macroref BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS] macro is a helper macro that places the same
|
||||
helpers as BOOST_TYPE_INDEX_REGISTER_CLASS plus some additional helpers for boost::typeindex::runtime_cast
|
||||
to function.
|
||||
|
||||
Issues with cross module type comparison on a bugged compilers are bypassed by directly comparing strings with type
|
||||
(latest versions of those compilers resolved that issue using exactly the same approach).
|
||||
|
||||
@ -262,6 +266,9 @@ Issues with cross module type comparison on a bugged compilers are bypassed by d
|
||||
[import ../examples/inheritance.cpp]
|
||||
[section Getting through the inheritance to receive a real type name ] [type_index_derived_example] [endsect]
|
||||
|
||||
[import ../examples/runtime_cast.cpp]
|
||||
[section Using runtime_cast where RTTI is unavailable or undesirable ] [type_index_runtime_cast_example] [endsect]
|
||||
|
||||
[import ../examples/exact_types_match.cpp]
|
||||
[section Exact type matching: storing type with const, volatile and reference qualifiers] [type_index_exact_type_match_example] [endsect]
|
||||
|
||||
|
@ -21,6 +21,7 @@ struct A {
|
||||
};
|
||||
struct B: public A { BOOST_TYPE_INDEX_REGISTER_CLASS };
|
||||
struct C: public B { BOOST_TYPE_INDEX_REGISTER_CLASS };
|
||||
struct D: public C { BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS) };
|
||||
|
||||
void print_real_type(const A& a) {
|
||||
std::cout << boost::typeindex::type_id_runtime(a).pretty_name() << '\n';
|
||||
@ -31,6 +32,15 @@ int main() {
|
||||
const A& c_as_a = c;
|
||||
print_real_type(c_as_a); // Outputs `struct C`
|
||||
print_real_type(B()); // Outputs `struct B`
|
||||
|
||||
/*`
|
||||
It's also possible to use type_id_runtime with the BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS, which adds additional
|
||||
information for runtime_cast to work.
|
||||
*/
|
||||
D c;
|
||||
const A& d_as_a = d;
|
||||
print_real_type(dc_as_a); // Outputs `struct D`
|
||||
|
||||
}
|
||||
|
||||
//] [/type_index_derived_example]
|
||||
|
78
examples/runtime_cast.cpp
Normal file
78
examples/runtime_cast.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
//
|
||||
// Copyright (c) Chris Glover, 2016.
|
||||
//
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
//[type_index_runtime_cast_example
|
||||
/*`
|
||||
The following example shows that `runtime_cast` is able to find a valid pointer
|
||||
in various class hierarchies regardless of inheritance or type relation.
|
||||
|
||||
Example works with and without RTTI."
|
||||
*/
|
||||
|
||||
#include <boost/type_index/runtime_cast.hpp>
|
||||
#include <iostream>
|
||||
|
||||
struct A {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
virtual ~A()
|
||||
{}
|
||||
};
|
||||
|
||||
struct B {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
virtual ~B()
|
||||
{}
|
||||
};
|
||||
|
||||
struct C : A {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((A))
|
||||
};
|
||||
|
||||
struct D : B {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((B))
|
||||
};
|
||||
|
||||
struct E : C, D {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((C)(D))
|
||||
};
|
||||
|
||||
int main() {
|
||||
C c;
|
||||
A* a = &c;
|
||||
|
||||
if(C* cp = boost::typeindex::runtime_cast<C*>(a))
|
||||
std::cout << "Yes, a points to a C." << '\n';
|
||||
else
|
||||
std::cout << "Error: Expected a to point to a C" << '\n';
|
||||
|
||||
if(E* ce = boost::typeindex::runtime_cast<E*>(a))
|
||||
std::cout << "Error: Expected a to not points to an E." << '\n';
|
||||
else
|
||||
std::cout << "But, a does not point to an E" << '\n';
|
||||
|
||||
E e;
|
||||
C* cp = &e;
|
||||
if(D* dp = boost::typeindex::runtime_cast<D*>(cp))
|
||||
std::cout << "Yes, we can cross-cast from a C* to a D* when we actually have an E." << '\n';
|
||||
else
|
||||
std::cout << "Error: Expected cp to point to a D" << '\n';
|
||||
|
||||
/*`
|
||||
Alternatively, we can use runtime_pointer_cast so we don't need to specity the target as a pointer.
|
||||
This works for smart_ptr types too.
|
||||
*/
|
||||
A* ap = &e;
|
||||
if(B* bp = boost::typeindex::runtime_pointer_cast<B>(ap))
|
||||
std::cout << "Yes, we can cross-cast and up-cast at the same time." << '\n';
|
||||
else
|
||||
std::cout << "Error: Expected ap to point to a B" << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//] [/type_index_runtime_cast_example]
|
@ -12,6 +12,10 @@
|
||||
/// \file runtime_cast.hpp
|
||||
/// \brief Contains the basic utilities necessary to fully emulate
|
||||
/// dynamic_cast for language level constructs (raw pointers and references).
|
||||
///
|
||||
/// boost::typeindex::runtime_cast is a drop in replacement for dynamic_cast
|
||||
/// that can be used in situations where traditional rtti is either unavailable
|
||||
/// or undesirable.
|
||||
|
||||
#include <boost/type_index/runtime_cast/register_runtime_class.hpp>
|
||||
#include <boost/type_index/runtime_cast/pointer_cast.hpp>
|
||||
|
@ -23,6 +23,16 @@
|
||||
|
||||
namespace boost { namespace typeindex {
|
||||
|
||||
/// \brief Creates a new instance of std::shared_ptr whose stored pointer is obtained from u's
|
||||
/// stored pointer using a runtime_cast.
|
||||
///
|
||||
/// The new shared_ptr will share ownership with u, except that it is empty if the runtime_cast
|
||||
/// performed by runtime_pointer_cast returns a null pointer.
|
||||
/// \tparam T The desired target type to return a pointer of.
|
||||
/// \tparam U A complete class type of the source instance pointed to from u.
|
||||
/// \return If there exists a valid conversion from U* to T*, returns a boost::shared_ptr<T>
|
||||
/// that points to an address suitably offset from u.
|
||||
/// If no such conversion exists, returns boost::shared_ptr<T>();
|
||||
template<typename T, typename U>
|
||||
boost::shared_ptr<T> runtime_pointer_cast(boost::shared_ptr<U> const& u) {
|
||||
T* value = detail::runtime_cast_impl<T>(u.get(), boost::is_base_and_derived<T, U>());
|
||||
|
@ -10,13 +10,8 @@
|
||||
#define BOOST_TYPE_INDEX_RUNTIME_CAST_POINTER_CAST_HPP
|
||||
|
||||
/// \file pointer_class.hpp
|
||||
/// \brief Contains the overload of boost::typeindex::runtime_cast for
|
||||
/// \brief Contains the function overloads of boost::typeindex::runtime_cast for
|
||||
/// pointer types.
|
||||
///
|
||||
/// boost::typeindex::runtime_cast can be used to emulate dynamic_cast
|
||||
/// functionality on platorms that don't provide it or should the user
|
||||
/// desire opt in functionality instead of enabling it system wide.
|
||||
|
||||
#include <boost/type_index.hpp>
|
||||
#include <boost/type_index/runtime_cast/detail/runtime_cast_impl.hpp>
|
||||
#include <boost/type_traits/is_base_and_derived.hpp>
|
||||
@ -28,23 +23,47 @@
|
||||
|
||||
namespace boost { namespace typeindex {
|
||||
|
||||
/// \brief Safely converts pointers to classes up, down, and sideways along the inheritance hierarchy.
|
||||
/// \tparam T The desired target type. Like dynamic_cast, must be a pointer to complete class type.
|
||||
/// \tparam U A complete class type of the source instance, u.
|
||||
/// \return If there exists a valid conversion from U* to T, returns a T that points to
|
||||
/// an address suitably offset from u. If no such conversion exists, returns NULL.
|
||||
template<typename T, typename U>
|
||||
T runtime_cast(U* u) BOOST_NOEXCEPT {
|
||||
typedef typename boost::remove_pointer<T>::type impl_type;
|
||||
return detail::runtime_cast_impl<impl_type>(u, boost::is_base_and_derived<T, U>());
|
||||
}
|
||||
|
||||
/// \brief Safely converts pointers to classes up, down, and sideways along the inheritance hierarchy.
|
||||
/// \tparam T The desired target type. Like dynamic_cast, must be a pointer to complete class type.
|
||||
/// \tparam U A complete class type of the source instance, u.
|
||||
/// \return If there exists a valid conversion from U* to T, returns a T that points to
|
||||
/// an address suitably offset from u. If no such conversion exists, returns NULL.
|
||||
template<typename T, typename U>
|
||||
T runtime_cast(U const* u) BOOST_NOEXCEPT {
|
||||
typedef typename boost::remove_pointer<T>::type impl_type;
|
||||
return detail::runtime_cast_impl<impl_type>(u, boost::is_base_and_derived<T, U>());
|
||||
}
|
||||
|
||||
/// \brief Safely converts pointers to classes up, down, and sideways along the inheritance
|
||||
/// hierarchy.
|
||||
/// \tparam T The desired target type to return a pointer to.
|
||||
/// \tparam U A complete class type of the source instance, u.
|
||||
/// \return If there exists a valid conversion from U const* to T*, returns a T*
|
||||
/// that points to an address suitably offset from u.
|
||||
/// If no such conversion exists, returns NULL.
|
||||
template<typename T, typename U>
|
||||
T* runtime_pointer_cast(U* u) BOOST_NOEXCEPT {
|
||||
return detail::runtime_cast_impl<T>(u, boost::is_base_and_derived<T, U>());
|
||||
}
|
||||
|
||||
/// \brief Safely converts pointers to classes up, down, and sideways along the inheritance
|
||||
/// hierarchy.
|
||||
/// \tparam T The desired target type to return a pointer to.
|
||||
/// \tparam U A complete class type of the source instance, u.
|
||||
/// \return If there exists a valid conversion from U const* to T const*, returns a T const*
|
||||
/// that points to an address suitably offset from u.
|
||||
/// If no such conversion exists, returns NULL.
|
||||
template<typename T, typename U>
|
||||
T const* runtime_pointer_cast(U const* u) BOOST_NOEXCEPT {
|
||||
return detail::runtime_cast_impl<T>(u, boost::is_base_and_derived<T, U>());
|
||||
|
@ -6,8 +6,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_TYPE_INDEX_RUNTIME_REFERENCE_CAST_HPP
|
||||
#define BOOST_TYPE_INDEX_RUNTIME_REFERENCE_CAST_HPP
|
||||
#ifndef BOOST_TYPE_INDEX_RUNTIME_CAST_REFERENCE_CAST_HPP
|
||||
#define BOOST_TYPE_INDEX_RUNTIME_CAST_REFERENCE_CAST_HPP
|
||||
|
||||
/// \file reference_cast.hpp
|
||||
/// \brief Contains the overload of boost::typeindex::runtime_cast for
|
||||
@ -25,6 +25,11 @@
|
||||
|
||||
namespace boost { namespace typeindex {
|
||||
|
||||
/// \brief Safely converts references to classes up, down, and sideways along the inheritance hierarchy.
|
||||
/// \tparam T The desired target type. Like dynamic_cast, must be a pointer to complete class type.
|
||||
/// \tparam U A complete class type of the source instance, u.
|
||||
/// \return If there exists a valid conversion from U& to T, returns a T that references an address
|
||||
/// suitably offset from u. If no such conversion exists, throws std::bad_cast()
|
||||
template<typename T, typename U>
|
||||
T& runtime_cast(U& u) {
|
||||
typedef typename boost::remove_reference<T>::type impl_type;
|
||||
@ -34,6 +39,11 @@ T& runtime_cast(U& u) {
|
||||
return *value;
|
||||
}
|
||||
|
||||
/// \brief Safely converts references to classes up, down, and sideways along the inheritance hierarchy.
|
||||
/// \tparam T The desired target type. Like dynamic_cast, must be a pointer to complete class type.
|
||||
/// \tparam U A complete class type of the source instance, u.
|
||||
/// \return If there exists a valid conversion from U const& to T const, returns a T const that references an address
|
||||
/// suitably offset from u. If no such conversion exists, throws std::bad_cast()
|
||||
template<typename T, typename U>
|
||||
T const& runtime_cast(U const& u) {
|
||||
typedef typename boost::remove_reference<T>::type impl_type;
|
||||
@ -45,4 +55,4 @@ T const& runtime_cast(U const& u) {
|
||||
|
||||
}} // namespace boost::typeindex
|
||||
|
||||
#endif // BOOST_TYPE_INDEX_RUNTIME_REFERENCE_CAST_HPP
|
||||
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_REFERENCE_CAST_HPP
|
@ -11,11 +11,6 @@
|
||||
|
||||
/// \file register_runtime_class.hpp
|
||||
/// \brief Contains the macro BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
|
||||
///
|
||||
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS is used to provide
|
||||
/// boost::typeindex::runtime_cast with the information necessary to perform
|
||||
/// the dynamic_cast emulation it was designed to do.
|
||||
|
||||
#include <boost/type_index.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
|
||||
@ -34,16 +29,60 @@ inline type_index runtime_class_construct_type_id(T const*) {
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// @cond
|
||||
|
||||
#define BOOST_TYPE_INDEX_CHECK_BASE_(r, data, Base) \
|
||||
if(void const* ret_val = this->Base::boost_type_index_find_instance_(idx)) return ret_val;
|
||||
|
||||
#define BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(base_list) \
|
||||
/// @endcond
|
||||
|
||||
/// \def BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS
|
||||
/// \brief Macro used to make a class compatible with boost::typeindex::runtime_cast
|
||||
///
|
||||
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS generates a virtual function
|
||||
/// in the current class that, when combined with the supplied base class information, allows
|
||||
/// boost::typeindex::runtime_cast to accurately convert between dynamic types of instances of
|
||||
/// the current class.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct base1 {
|
||||
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
/// virtual ~base1();
|
||||
/// };
|
||||
///
|
||||
/// struct base2 {
|
||||
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
/// virtual ~base2();
|
||||
/// };
|
||||
///
|
||||
/// struct derived1 : base1 {
|
||||
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base1))
|
||||
/// };
|
||||
///
|
||||
/// struct derived2 : base1, base2 {
|
||||
/// BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((base1)(base2))
|
||||
/// };
|
||||
///
|
||||
/// ...
|
||||
///
|
||||
/// base1* pb1 = get_object();
|
||||
/// if(derived2* pb2 = boost::typeindex::runtime_cast<derived2*>(pb1))
|
||||
/// { /* ... */ }
|
||||
/// \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.
|
||||
#define BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(base_class_seq) \
|
||||
BOOST_TYPE_INDEX_REGISTER_CLASS \
|
||||
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_list) \
|
||||
BOOST_PP_SEQ_FOR_EACH(BOOST_TYPE_INDEX_CHECK_BASE_, _, base_class_seq) \
|
||||
return NULL; \
|
||||
}
|
||||
}} // namespace boost::typeindex
|
||||
|
||||
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_HPP
|
||||
#define BOOST_TYPE_INDEX_NO_BASE_CLASS BOOST_PP_SEQ_NIL
|
||||
|
||||
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_REGISTER_RUNTIME_CLASS_HPP
|
@ -9,7 +9,7 @@
|
||||
#ifndef BOOST_TYPE_INDEX_RUNTIME_CAST_STD_SHARED_PTR_CAST_HPP
|
||||
#define BOOST_TYPE_INDEX_RUNTIME_CAST_STD_SHARED_PTR_CAST_HPP
|
||||
|
||||
/// \file boost_shared_ptr_cast.hpp
|
||||
/// \file std_shared_ptr_cast.hpp
|
||||
/// \brief Contains the overload of boost::typeindex::runtime_pointer_cast for
|
||||
/// std::shared_ptr types.
|
||||
|
||||
@ -23,6 +23,16 @@
|
||||
|
||||
namespace boost { namespace typeindex {
|
||||
|
||||
/// \brief Creates a new instance of std::shared_ptr whose stored pointer is obtained from u's
|
||||
/// stored pointer using a runtime_cast.
|
||||
///
|
||||
/// The new shared_ptr will share ownership with u, except that it is empty if the runtime_cast
|
||||
/// performed by runtime_pointer_cast returns a null pointer.
|
||||
/// \tparam T The desired target type to return a pointer of.
|
||||
/// \tparam U A complete class type of the source instance pointed to from u.
|
||||
/// \return If there exists a valid conversion from U* to T*, returns a std::shared_ptr<T>
|
||||
/// that points to an address suitably offset from u.
|
||||
/// If no such conversion exists, returns std::shared_ptr<T>();
|
||||
template<typename T, typename U>
|
||||
std::shared_ptr<T> runtime_pointer_cast(std::shared_ptr<U> const& u) {
|
||||
T* value = detail::runtime_cast_impl<T>(u.get(), boost::is_base_and_derived<T, U>());
|
||||
@ -33,4 +43,4 @@ std::shared_ptr<T> runtime_pointer_cast(std::shared_ptr<U> const& u) {
|
||||
|
||||
}} // namespace boost::typeindex
|
||||
|
||||
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_BOOST_SHARED_PTR_CAST_HPP
|
||||
#endif // BOOST_TYPE_INDEX_RUNTIME_CAST_STD_SHARED_PTR_CAST_HPP
|
@ -26,7 +26,7 @@
|
||||
std::string name;
|
||||
|
||||
struct base {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_PP_SEQ_NIL)
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
IMPLEMENT_CLASS(base)
|
||||
};
|
||||
|
||||
@ -36,12 +36,12 @@ struct single_derived : base {
|
||||
};
|
||||
|
||||
struct base1 {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_PP_SEQ_NIL)
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
IMPLEMENT_CLASS(base1)
|
||||
};
|
||||
|
||||
struct base2 {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_PP_SEQ_NIL)
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
IMPLEMENT_CLASS(base2)
|
||||
};
|
||||
|
||||
@ -66,7 +66,7 @@ struct multiple_virtual_derived : baseV1, baseV2 {
|
||||
};
|
||||
|
||||
struct unrelated {
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_PP_SEQ_NIL)
|
||||
BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(BOOST_TYPE_INDEX_NO_BASE_CLASS)
|
||||
IMPLEMENT_CLASS(unrelated)
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user