summaryrefslogtreecommitdiff
path: root/libs/type_index
diff options
context:
space:
mode:
Diffstat (limited to 'libs/type_index')
-rw-r--r--libs/type_index/README.md2
-rw-r--r--libs/type_index/doc/Jamfile.v210
-rw-r--r--libs/type_index/doc/autodoc.xml248
-rw-r--r--libs/type_index/doc/type_index.qbk7
-rw-r--r--libs/type_index/examples/constexpr14_namespace_check.cpp7
-rw-r--r--libs/type_index/examples/constexpr14_sort_check.cpp2
-rw-r--r--libs/type_index/examples/exact_types_match.cpp2
-rw-r--r--libs/type_index/examples/inheritance.cpp11
-rw-r--r--libs/type_index/examples/registry.cpp1
-rw-r--r--libs/type_index/examples/runtime_cast.cpp90
-rw-r--r--libs/type_index/examples/user_defined_typeinfo.hpp8
-rw-r--r--libs/type_index/test/Jamfile.v21
-rw-r--r--libs/type_index/test/type_index_constexpr_test.cpp1
-rw-r--r--libs/type_index/test/type_index_runtime_cast_test.cpp296
-rw-r--r--libs/type_index/test/type_index_test.cpp1
15 files changed, 680 insertions, 7 deletions
diff --git a/libs/type_index/README.md b/libs/type_index/README.md
index 6cfc10f7dc..4a99a28d97 100644
--- a/libs/type_index/README.md
+++ b/libs/type_index/README.md
@@ -1,4 +1,4 @@
-#[Boost.TypeIndex](http://boost.org/libs/type_index)
+# [Boost.TypeIndex](http://boost.org/libs/type_index)
Boost.TypeIndex is a part of the [Boost C++ Libraries](http://github.com/boostorg). It is a runtime/compile time copyable type info.
### Test results
diff --git a/libs/type_index/doc/Jamfile.v2 b/libs/type_index/doc/Jamfile.v2
index 53d6d7d355..6ebc089df5 100644
--- a/libs/type_index/doc/Jamfile.v2
+++ b/libs/type_index/doc/Jamfile.v2
@@ -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
@@ -35,3 +36,12 @@ boostbook standalone
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
;
+###############################################################################
+alias boostdoc
+ : type_index
+ :
+ : <dependency>autodoc
+ : ;
+explicit boostdoc ;
+alias boostrelease ;
+explicit boostrelease ;
diff --git a/libs/type_index/doc/autodoc.xml b/libs/type_index/doc/autodoc.xml
index 4b6d5345dc..f3981ab50a 100644
--- a/libs/type_index/doc/autodoc.xml
+++ b/libs/type_index/doc/autodoc.xml
@@ -39,6 +39,14 @@ std::cout &lt;&lt; ti.pretty_name(); // Outputs 'Derived'
+
+
+
+
+
+
+
+
</namespace>
</namespace>
@@ -119,6 +127,228 @@ See <ulink url="boost_typeindex/rtti_emulation_limitations.html">RTTI emulation
<function name="ctti_construct"><type><emphasis>unspecified</emphasis></type><template>
<template-type-parameter name="T"/>
</template><purpose>Helper method for getting <classname alt="boost::typeindex::detail::ctti_data">detail::ctti_data</classname> of a template parameter T. </purpose></function>
+
+
+
+
+
+
+
+
+</namespace>
+
+</namespace>
+</header>
+<header name="boost/type_index/runtime_cast.hpp">
+<para>Contains the basic utilities necessary to fully emulate dynamic_cast for language level constructs (raw pointers and references). </para><para>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. </para></header>
+<header name="boost/type_index/runtime_cast/boost_shared_ptr_cast.hpp">
+<para>Contains the overload of boost::typeindex::runtime_pointer_cast for boost::shared_ptr types. </para><namespace name="boost">
+<namespace name="typeindex">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<function name="runtime_pointer_cast"><type>boost::shared_ptr&lt; T &gt;</type><template>
+ <template-type-parameter name="T"><purpose><para>The desired target type to return a pointer of. </para></purpose></template-type-parameter>
+ <template-type-parameter name="U"><purpose><para>A complete class type of the source instance pointed to from u. </para></purpose></template-type-parameter>
+ </template><parameter name="u"><paramtype>boost::shared_ptr&lt; U &gt; const &amp;</paramtype></parameter><purpose>Creates a new instance of std::shared_ptr whose stored pointer is obtained from u's stored pointer using a runtime_cast. </purpose><description><para>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.
+
+</para></description><returns><para>If there exists a valid conversion from U* to T*, returns a boost::shared_ptr&lt;T&gt; that points to an address suitably offset from u. If no such conversion exists, returns boost::shared_ptr&lt;T&gt;(); </para></returns></function>
+</namespace>
+
+</namespace>
+</header>
+<header name="boost/type_index/runtime_cast/pointer_cast.hpp">
+<namespace name="boost">
+<namespace name="typeindex">
+
+
+
+
+
+
+
+
+
+
+
+
+<function name="runtime_cast"><type>T</type><template>
+ <template-type-parameter name="T"><purpose><para>The desired target type. Like dynamic_cast, must be a pointer to complete class type. </para></purpose></template-type-parameter>
+ <template-type-parameter name="U"><purpose><para>A complete class type of the source instance, u. </para></purpose></template-type-parameter>
+ </template><parameter name="u"><paramtype>U *</paramtype></parameter><purpose>Safely converts pointers to classes up, down, and sideways along the inheritance hierarchy. </purpose><description><para>
+
+</para></description><returns><para>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. </para></returns></function>
+<function name="runtime_cast"><type>T</type><template>
+ <template-type-parameter name="T"><purpose><para>The desired target type. Like dynamic_cast, must be a pointer to complete class type. </para></purpose></template-type-parameter>
+ <template-type-parameter name="U"><purpose><para>A complete class type of the source instance, u. </para></purpose></template-type-parameter>
+ </template><parameter name="u"><paramtype>U const *</paramtype></parameter><purpose>Safely converts pointers to classes up, down, and sideways along the inheritance hierarchy. </purpose><description><para>
+
+</para></description><returns><para>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. </para></returns></function>
+<function name="runtime_pointer_cast"><type>T *</type><template>
+ <template-type-parameter name="T"><purpose><para>The desired target type to return a pointer to. </para></purpose></template-type-parameter>
+ <template-type-parameter name="U"><purpose><para>A complete class type of the source instance, u. </para></purpose></template-type-parameter>
+ </template><parameter name="u"><paramtype>U *</paramtype></parameter><purpose>Safely converts pointers to classes up, down, and sideways along the inheritance hierarchy. </purpose><description><para>
+
+</para></description><returns><para>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. </para></returns></function>
+<function name="runtime_pointer_cast"><type>T const *</type><template>
+ <template-type-parameter name="T"><purpose><para>The desired target type to return a pointer to. </para></purpose></template-type-parameter>
+ <template-type-parameter name="U"><purpose><para>A complete class type of the source instance, u. </para></purpose></template-type-parameter>
+ </template><parameter name="u"><paramtype>U const *</paramtype></parameter><purpose>Safely converts pointers to classes up, down, and sideways along the inheritance hierarchy. </purpose><description><para>
+
+</para></description><returns><para>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. </para></returns></function>
+
+</namespace>
+
+</namespace>
+</header>
+<header name="boost/type_index/runtime_cast/reference_cast.hpp">
+<para>Contains the overload of boost::typeindex::runtime_cast for reference types. </para><namespace name="boost">
+<namespace name="typeindex">
+<struct name="bad_runtime_cast"><inherit access="public">exception</inherit><purpose>Indicates that runtime_cast was unable to perform the desired cast operation because the source instance was not also an instance of the target type. </purpose></struct>
+
+
+
+
+
+
+
+
+
+<function name="runtime_cast"><type>boost::add_reference&lt; T &gt;::type</type><template>
+ <template-type-parameter name="T"><purpose><para>The desired target type. Like dynamic_cast, must be a pointer to complete class type. </para></purpose></template-type-parameter>
+ <template-type-parameter name="U"><purpose><para>A complete class type of the source instance, u. </para></purpose></template-type-parameter>
+ </template><parameter name="u"><paramtype>U &amp;</paramtype></parameter><purpose>Safely converts references to classes up, down, and sideways along the inheritance hierarchy. </purpose><description><para>
+
+</para></description><returns><para>If there exists a valid conversion from U&amp; to T, returns a T that references an address suitably offset from u. If no such conversion exists, throws <classname alt="boost::typeindex::bad_runtime_cast">boost::typeindex::bad_runtime_cast</classname>. </para></returns></function>
+<function name="runtime_cast"><type>boost::add_reference&lt; const T &gt;::type</type><template>
+ <template-type-parameter name="T"><purpose><para>The desired target type. Like dynamic_cast, must be a pointer to complete class type. </para></purpose></template-type-parameter>
+ <template-type-parameter name="U"><purpose><para>A complete class type of the source instance, u. </para></purpose></template-type-parameter>
+ </template><parameter name="u"><paramtype>U const &amp;</paramtype></parameter><purpose>Safely converts references to classes up, down, and sideways along the inheritance hierarchy. </purpose><description><para>
+
+</para></description><returns><para>If there exists a valid conversion from U const&amp; to T const, returns a T const that references an address suitably offset from u. If no such conversion exists, throws <classname alt="boost::typeindex::bad_runtime_cast">boost::typeindex::bad_runtime_cast</classname>. </para></returns></function>
+
+
+
+
+
+</namespace>
+
+</namespace>
+</header>
+<header name="boost/type_index/runtime_cast/register_runtime_class.hpp">
+<para>Contains the macros BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST and BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS. </para><namespace name="boost">
+<namespace name="typeindex">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</namespace>
+
+</namespace>
+<macro name="BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS" kind="functionlike"><macro-parameter name="base_class_seq"><description><para>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. </para></description></macro-parameter><purpose>Macro used to make a class compatible with boost::typeindex::runtime_cast. </purpose><description><para>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.</para><para>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.</para><para><emphasis role="bold">Example:</emphasis> <programlisting language="c++">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&lt;derived2*&gt;(pb1)) {
+ assert(boost::typeindex::type_id_runtime(*pb1)) == boost::typeindex::type_id&lt;derived2&gt;());
+}
+</programlisting></para><para>
+</para></description></macro>
+<macro name="BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST" kind="functionlike"><macro-parameter name="base_class_seq"><description><para>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. </para></description></macro-parameter><purpose>Macro used to make a class compatible with boost::typeindex::runtime_cast without including support for boost::typeindex::type_id_runtime. </purpose><description><para>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.</para><para><emphasis role="bold">Example:</emphasis> <programlisting language="c++">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&lt;derived2*&gt;(pb1))
+{ /* can't call boost::typeindex::type_id_runtime(*pb1) here */ }
+</programlisting></para><para>
+</para></description></macro>
+<macro name="BOOST_TYPE_INDEX_NO_BASE_CLASS"><purpose>Instructs BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS and BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST that this class has no base classes. </purpose></macro>
+</header>
+<header name="boost/type_index/runtime_cast/std_shared_ptr_cast.hpp">
+<para>Contains the overload of boost::typeindex::runtime_pointer_cast for std::shared_ptr types. </para><namespace name="boost">
+<namespace name="typeindex">
+
+
+
+
+
+
+
+
+
+<function name="runtime_pointer_cast"><type>std::shared_ptr&lt; T &gt;</type><template>
+ <template-type-parameter name="T"><purpose><para>The desired target type to return a pointer of. </para></purpose></template-type-parameter>
+ <template-type-parameter name="U"><purpose><para>A complete class type of the source instance pointed to from u. </para></purpose></template-type-parameter>
+ </template><parameter name="u"><paramtype>std::shared_ptr&lt; U &gt; const &amp;</paramtype></parameter><purpose>Creates a new instance of std::shared_ptr whose stored pointer is obtained from u's stored pointer using a runtime_cast. </purpose><description><para>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.
+
+</para></description><returns><para>If there exists a valid conversion from U* to T*, returns a std::shared_ptr&lt;T&gt; that points to an address suitably offset from u. If no such conversion exists, returns std::shared_ptr&lt;T&gt;(); </para></returns></function>
+
+
+
+
+
+
+
</namespace>
</namespace>
@@ -158,6 +388,14 @@ See <ulink url="boost_typeindex/rtti_emulation_limitations.html">RTTI emulation
+
+
+
+
+
+
+
+
</namespace>
</namespace>
@@ -195,7 +433,7 @@ public:
<method name="before" cv="const noexcept"><type>bool</type><parameter name="rhs"><paramtype>const Derived &amp;</paramtype></parameter><description><para><emphasis role="bold">Override:</emphasis> This function <emphasis role="bold">may</emphasis> be redefined in Derived class. Overrides <emphasis role="bold">must</emphasis> not throw.
</para></description><returns><para>True if rhs is greater than this. By default compares types by raw_name(). </para></returns></method>
<method name="hash_code" cv="const noexcept"><type>std::size_t</type><description><para><emphasis role="bold">Override:</emphasis> This function <emphasis role="bold">may</emphasis> be redefined in Derived class. Overrides <emphasis role="bold">must</emphasis> not throw.
-<note><para>&lt;boost/functional/hash.hpp&gt; has to be included if this function is used. </para></note>
+<note><para>Derived class header <emphasis role="bold">must</emphasis> include &lt;boost/functional/hash.hpp&gt;, <emphasis role="bold">unless</emphasis> this function is redefined in Derived class to not use boost::hash_range(). </para></note>
</para></description><returns><para>Hash code of a type. By default hashes types by raw_name(). </para></returns></method>
</method-group>
<method-group name="protected member functions">
@@ -239,6 +477,14 @@ public:
</template><parameter name="lhs"><paramtype>const <classname>type_index_facade</classname>&lt; Derived, TypeInfo &gt; &amp;</paramtype></parameter><description><para>This free function is used by Boost's unordered containers. <note><para>&lt;boost/functional/hash.hpp&gt; has to be included if this function is used. </para></note>
</para></description></function>
+
+
+
+
+
+
+
+
</namespace>
<function name="hash_range"><type>std::size_t</type><template>
<template-type-parameter name="It"/>
diff --git a/libs/type_index/doc/type_index.qbk b/libs/type_index/doc/type_index.qbk
index 27d8777ca6..539fc83be7 100644
--- a/libs/type_index/doc/type_index.qbk
+++ b/libs/type_index/doc/type_index.qbk
@@ -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]
diff --git a/libs/type_index/examples/constexpr14_namespace_check.cpp b/libs/type_index/examples/constexpr14_namespace_check.cpp
index 0752e08074..98a5e40fff 100644
--- a/libs/type_index/examples/constexpr14_namespace_check.cpp
+++ b/libs/type_index/examples/constexpr14_namespace_check.cpp
@@ -1,4 +1,4 @@
-// Copyright 2013-2016 Antony Polukhin
+// Copyright 2013-2017 Antony Polukhin
// Distributed under the Boost Software License, Version 1.0.
// (See the accompanying file LICENSE_1_0.txt
@@ -6,6 +6,10 @@
#include <boost/config.hpp>
+template <class T>
+void do_something(const T&) {}
+
+
#if !defined(BOOST_NO_CXX14_CONSTEXPR) && !defined(BOOST_NO_CXX11_CONSTEXPR)
// Implementation of this function is not essential for the example
template <std::size_t N>
@@ -62,6 +66,7 @@ namespace my_project {
// Actual implementation of the serialization goes below
// ...
+ do_something(value);
}
};
diff --git a/libs/type_index/examples/constexpr14_sort_check.cpp b/libs/type_index/examples/constexpr14_sort_check.cpp
index 5443924f7c..452b98a0ec 100644
--- a/libs/type_index/examples/constexpr14_sort_check.cpp
+++ b/libs/type_index/examples/constexpr14_sort_check.cpp
@@ -55,7 +55,7 @@ constexpr bool is_asc_sorted(types<Lhs, Rhs, TN...>) noexcept {
// Using the newly created `is_asc_sorted` trait:
template <class... T>
-void do_something(const types<T...>& t) noexcept {
+void do_something(const types<T...>& /*value*/) noexcept {
static_assert(
is_asc_sorted( types<T...>() ),
"T... for do_something(const types<T...>& t) must be sorted ascending"
diff --git a/libs/type_index/examples/exact_types_match.cpp b/libs/type_index/examples/exact_types_match.cpp
index f245066ef3..498d662b73 100644
--- a/libs/type_index/examples/exact_types_match.cpp
+++ b/libs/type_index/examples/exact_types_match.cpp
@@ -17,6 +17,8 @@
#include <boost/type_index.hpp>
#include <iostream>
#include <stdexcept>
+#include <cstdlib>
+
//<-
// Making `#include <cassert>` visible in docs, while actually using hand-made check
// instead of `assert`. This is required to verify correct behavior even if NDEBUG
diff --git a/libs/type_index/examples/inheritance.cpp b/libs/type_index/examples/inheritance.cpp
index c2634397e0..3da75271e8 100644
--- a/libs/type_index/examples/inheritance.cpp
+++ b/libs/type_index/examples/inheritance.cpp
@@ -13,6 +13,7 @@
*/
#include <boost/type_index.hpp>
+#include <boost/type_index/runtime_cast/register_runtime_class.hpp>
#include <iostream>
struct A {
@@ -21,6 +22,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 +33,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 d;
+ const A& d_as_a = d;
+ print_real_type(d_as_a); // Outputs `struct D`
+
}
//] [/type_index_derived_example]
diff --git a/libs/type_index/examples/registry.cpp b/libs/type_index/examples/registry.cpp
index 091b0908db..4f1eaa8683 100644
--- a/libs/type_index/examples/registry.cpp
+++ b/libs/type_index/examples/registry.cpp
@@ -12,7 +12,6 @@
#include <boost/type_index.hpp>
#include <boost/unordered_set.hpp>
-#include <boost/functional/hash.hpp>
//<-
// Making `#include <cassert>` visible in docs, while actually using `BOOST_TEST`
// instead of `assert`. This is required to verify correct behavior even if NDEBUG
diff --git a/libs/type_index/examples/runtime_cast.cpp b/libs/type_index/examples/runtime_cast.cpp
new file mode 100644
index 0000000000..43e7aa70f4
--- /dev/null
+++ b/libs/type_index/examples/runtime_cast.cpp
@@ -0,0 +1,90 @@
+//
+// 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: "
+ << a << "->" << cp << '\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: "
+ << a << "->" << ce << '\n';
+ }
+ else {
+ std::cout << "But, a does not point to an E" << '\n';
+ }
+
+ E e;
+ C* cp2 = &e;
+ if(D* dp = boost::typeindex::runtime_cast<D*>(cp2)) {
+ std::cout << "Yes, we can cross-cast from a C* to a D* when we actually have an E: "
+ << cp2 << "->" << dp << '\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."
+ << ap << "->" << bp << '\n';
+ }
+ else {
+ std::cout << "Error: Expected ap to point to a B" << '\n';
+ }
+
+ return 0;
+}
+
+//] [/type_index_runtime_cast_example]
diff --git a/libs/type_index/examples/user_defined_typeinfo.hpp b/libs/type_index/examples/user_defined_typeinfo.hpp
index 5690a00223..dc2caab643 100644
--- a/libs/type_index/examples/user_defined_typeinfo.hpp
+++ b/libs/type_index/examples/user_defined_typeinfo.hpp
@@ -70,7 +70,15 @@ namespace my_namespace { namespace detail {
`my_type_index` is a user created type_index class. If in doubt during this phase, you can always
take a look at the `<boost/type_index/ctti_type_index.hpp>` or `<boost/type_index/stl_type_index.hpp>`
files. Documentation for `type_index_facade` could be also useful.
+*/
+/*`
+ Since we are not going to override `type_index_facade::hash_code()` we must additionally include
+ `<boost/functional/hash.hpp>`.
+*/
+#include <boost/functional/hash.hpp>
+
+/*`
See implementation of `my_type_index`:
*/
namespace my_namespace {
diff --git a/libs/type_index/test/Jamfile.v2 b/libs/type_index/test/Jamfile.v2
index 6986c96527..8a1d3a46f8 100644
--- a/libs/type_index/test/Jamfile.v2
+++ b/libs/type_index/test/Jamfile.v2
@@ -40,6 +40,7 @@ exe testing_crossmodule_anonymous_no_rtti : testing_crossmodule_anonymous.cpp te
test-suite type_index
:
[ run type_index_test.cpp ]
+ [ run type_index_runtime_cast_test.cpp ]
[ run type_index_constexpr_test.cpp ]
[ run type_index_test.cpp : : : <rtti>off $(norttidefines) : type_index_test_no_rtti ]
[ run ctti_print_name.cpp : : : <test-info>always_show_run_output ]
diff --git a/libs/type_index/test/type_index_constexpr_test.cpp b/libs/type_index/test/type_index_constexpr_test.cpp
index e895d7b362..acc55e9ed9 100644
--- a/libs/type_index/test/type_index_constexpr_test.cpp
+++ b/libs/type_index/test/type_index_constexpr_test.cpp
@@ -7,7 +7,6 @@
#include <boost/type_index/ctti_type_index.hpp>
-#include <boost/functional/hash.hpp>
#include <boost/lexical_cast.hpp>
#include <algorithm>
#include <string>
diff --git a/libs/type_index/test/type_index_runtime_cast_test.cpp b/libs/type_index/test/type_index_runtime_cast_test.cpp
new file mode 100644
index 0000000000..1f5344ef5e
--- /dev/null
+++ b/libs/type_index/test/type_index_runtime_cast_test.cpp
@@ -0,0 +1,296 @@
+//
+// Copyright 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)
+
+// #include <boost/type_index/runtime_cast.hpp>
+// #include <boost/type_index/runtime_reference_cast.hpp>
+
+#include <boost/type_index/runtime_cast.hpp>
+#include <boost/type_index/runtime_cast/boost_shared_ptr_cast.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <boost/core/lightweight_test.hpp>
+
+#if !defined(BOOST_NO_CXX11_SMART_PTR)
+# include <boost/type_index/runtime_cast/std_shared_ptr_cast.hpp>
+#endif
+
+// Classes include a member variable "name" with the
+// name of the class hard coded so we can be sure that
+// the pointer offsets are all working, since we're doing
+// a cast from void* at some point.
+
+#define IMPLEMENT_CLASS(type_name) \
+ type_name() : name( #type_name ) {} \
+ std::string name;
+
+struct base {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
+ IMPLEMENT_CLASS(base)
+};
+
+struct single_derived : base {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
+ IMPLEMENT_CLASS(single_derived)
+};
+
+struct base1 {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
+ IMPLEMENT_CLASS(base1)
+};
+
+struct base2 {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
+ IMPLEMENT_CLASS(base2)
+};
+
+struct multiple_derived : base1, base2 {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base1)(base2))
+ IMPLEMENT_CLASS(multiple_derived)
+};
+
+struct baseV1 : virtual base {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
+ IMPLEMENT_CLASS(baseV1)
+};
+
+struct baseV2 : virtual base {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
+ IMPLEMENT_CLASS(baseV2)
+};
+
+struct multiple_virtual_derived : baseV1, baseV2 {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((baseV1)(baseV2))
+ IMPLEMENT_CLASS(multiple_virtual_derived)
+};
+
+struct unrelated {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
+ IMPLEMENT_CLASS(unrelated)
+};
+
+struct unrelated_with_base : base {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
+ IMPLEMENT_CLASS(unrelated_with_base)
+};
+
+struct unrelatedV1 : virtual base {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
+ IMPLEMENT_CLASS(unrelatedV1)
+};
+
+struct level1_a : base {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
+ IMPLEMENT_CLASS(level1_a)
+};
+
+struct level1_b : base {
+ BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST((base))
+ IMPLEMENT_CLASS(level1_b)
+};
+
+struct level2 : 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;
+ base b;
+ base* b2 = runtime_pointer_cast<base>(&b);
+ BOOST_TEST_NE(b2, (base*)NULL);
+ BOOST_TEST_EQ(b2->name, "base");
+
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&b), (unrelated*)NULL);
+ BOOST_TEST_EQ(runtime_pointer_cast<single_derived>(&b), (single_derived*)NULL);
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelatedV1>(&b), (unrelatedV1*)NULL);
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(&b), (unrelated_with_base*)NULL);
+}
+
+void single_base()
+{
+ using namespace boost::typeindex;
+ single_derived d;
+ base* b = &d;
+ single_derived* d2 = runtime_pointer_cast<single_derived>(b);
+ BOOST_TEST_NE(d2, (single_derived*)NULL);
+ BOOST_TEST_EQ(d2->name, "single_derived");
+
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&d), (unrelated*)NULL);
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL);
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(b), (unrelated_with_base*)NULL);
+}
+
+void multiple_base()
+{
+ using namespace boost::typeindex;
+ multiple_derived d;
+ base1* b1 = &d;
+ multiple_derived* d2 = runtime_pointer_cast<multiple_derived>(b1);
+ BOOST_TEST_NE(d2, (multiple_derived*)NULL);
+ BOOST_TEST_EQ(d2->name, "multiple_derived");
+
+ base2* b2 = runtime_pointer_cast<base2>(b1);
+ BOOST_TEST_NE(b2, (base2*)NULL);
+ BOOST_TEST_EQ(b2->name, "base2");
+
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&d), (unrelated*)NULL);
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b1), (unrelated*)NULL);
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(b1), (unrelated_with_base*)NULL);
+}
+
+void virtual_base()
+{
+ using namespace boost::typeindex;
+ multiple_virtual_derived d;
+ base* b = &d;
+ multiple_virtual_derived* d2 = runtime_pointer_cast<multiple_virtual_derived>(b);
+ baseV1* bv1 = runtime_pointer_cast<baseV1>(b);
+ baseV2* bv2 = runtime_pointer_cast<baseV2>(b);
+
+ BOOST_TEST_NE(d2, (multiple_virtual_derived*)NULL);
+ BOOST_TEST_EQ(d2->name, "multiple_virtual_derived");
+
+ BOOST_TEST_NE(bv1, (baseV1*)NULL);
+ BOOST_TEST_EQ(bv1->name, "baseV1");
+
+ BOOST_TEST_NE(bv2, (baseV2*)NULL);
+ BOOST_TEST_EQ(bv2->name, "baseV2");
+
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL);
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&d), (unrelated*)NULL);
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(b), (unrelated_with_base*)NULL);
+}
+
+void pointer_interface()
+{
+ using namespace boost::typeindex;
+ single_derived d;
+ base* b = &d;
+ single_derived* d2 = runtime_cast<single_derived*>(b);
+ BOOST_TEST_NE(d2, (single_derived*)NULL);
+ BOOST_TEST_EQ(d2->name, "single_derived");
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL);
+}
+
+void reference_interface()
+{
+ using namespace boost::typeindex;
+ single_derived d;
+ base& b = d;
+ single_derived& d2 = runtime_cast<single_derived&>(b);
+ BOOST_TEST_EQ(d2.name, "single_derived");
+
+ try {
+ unrelated& u = runtime_cast<unrelated&>(b);
+ (void)u;
+ BOOST_TEST(!"should throw bad_runtime_cast");
+ }
+ catch(boost::typeindex::bad_runtime_cast&) {
+ }
+ catch(...) {
+ BOOST_TEST(!"should throw bad_runtime_cast");
+ }
+}
+
+void const_pointer_interface()
+{
+ using namespace boost::typeindex;
+ const single_derived d;
+ base const* b = &d;
+ single_derived const* d2 = runtime_cast<single_derived const*>(b);
+ BOOST_TEST_NE(d2, (single_derived*)NULL);
+ BOOST_TEST_EQ(d2->name, "single_derived");
+ BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL);
+}
+
+void const_reference_interface()
+{
+ using namespace boost::typeindex;
+ const single_derived d;
+ base const& b = d;
+ single_derived const& d2 = runtime_cast<single_derived const&>(b);
+ BOOST_TEST_EQ(d2.name, "single_derived");
+
+ try {
+ unrelated const& u = runtime_cast<unrelated const&>(b);
+ (void)u;
+ BOOST_TEST(!"should throw bad_runtime_cast");
+ }
+ catch(boost::typeindex::bad_runtime_cast&) {
+ }
+ catch(...) {
+ BOOST_TEST(!"should throw bad_runtime_cast");
+ }
+}
+
+void diamond_non_virtual()
+{
+ using namespace boost::typeindex;
+ level2 inst;
+ level1_a* l1a = &inst;
+ base* b1 = l1a;
+ level1_b* l1_b = runtime_cast<level1_b*>(b1);
+ BOOST_TEST_NE(l1_b, (level1_b*)NULL);
+ BOOST_TEST_EQ(l1_b->name, "level1_b");
+}
+
+void boost_shared_ptr()
+{
+ using namespace boost::typeindex;
+ boost::shared_ptr<single_derived> d = boost::make_shared<single_derived>();
+ boost::shared_ptr<base> b = d;
+ boost::shared_ptr<single_derived> d2 = runtime_pointer_cast<single_derived>(b);
+ BOOST_TEST_NE(d2, boost::shared_ptr<single_derived>());
+ BOOST_TEST_EQ(d2->name, "single_derived");
+}
+
+void std_shared_ptr()
+{
+#if !defined(BOOST_NO_CXX11_SMART_PTR)
+ using namespace boost::typeindex;
+ std::shared_ptr<single_derived> d = std::make_shared<single_derived>();
+ std::shared_ptr<base> b = d;
+ std::shared_ptr<single_derived> d2 = runtime_pointer_cast<single_derived>(b);
+ BOOST_TEST_NE(d2, std::shared_ptr<single_derived>());
+ BOOST_TEST_EQ(d2->name, "single_derived");
+#endif
+}
+
+void register_runtime_class()
+{
+ using namespace boost::typeindex;
+ reg_derived rd;
+ reg_base* rb = &rd;
+ reg_derived* prd = runtime_pointer_cast<reg_derived>(rb);
+ BOOST_TEST_NE(prd, (reg_derived*)NULL);
+ BOOST_TEST_EQ(type_id_runtime(*prd), type_id<reg_derived>());
+}
+
+int main() {
+ no_base();
+ single_derived();
+ multiple_base();
+ virtual_base();
+ pointer_interface();
+ reference_interface();
+ const_pointer_interface();
+ const_reference_interface();
+ diamond_non_virtual();
+ boost_shared_ptr();
+ std_shared_ptr();
+ register_runtime_class();
+ return boost::report_errors();
+}
diff --git a/libs/type_index/test/type_index_test.cpp b/libs/type_index/test/type_index_test.cpp
index c022812fd6..b7925d2ecf 100644
--- a/libs/type_index/test/type_index_test.cpp
+++ b/libs/type_index/test/type_index_test.cpp
@@ -7,7 +7,6 @@
#include <boost/type_index.hpp>
-#include <boost/functional/hash.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/core/lightweight_test.hpp>