Initial documentation.

This commit is contained in:
Chris Glover
2016-08-11 10:31:16 -04:00
parent 5af925602e
commit ad26256d09
11 changed files with 211 additions and 23 deletions

View File

@ -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

View File

@ -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]

View File

@ -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
View 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]

View File

@ -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>

View File

@ -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>());

View File

@ -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>());

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
};