diff options
Diffstat (limited to 'libs/type_index')
-rw-r--r-- | libs/type_index/README.md | 2 | ||||
-rw-r--r-- | libs/type_index/doc/Jamfile.v2 | 10 | ||||
-rw-r--r-- | libs/type_index/doc/autodoc.xml | 248 | ||||
-rw-r--r-- | libs/type_index/doc/type_index.qbk | 7 | ||||
-rw-r--r-- | libs/type_index/examples/constexpr14_namespace_check.cpp | 7 | ||||
-rw-r--r-- | libs/type_index/examples/constexpr14_sort_check.cpp | 2 | ||||
-rw-r--r-- | libs/type_index/examples/exact_types_match.cpp | 2 | ||||
-rw-r--r-- | libs/type_index/examples/inheritance.cpp | 11 | ||||
-rw-r--r-- | libs/type_index/examples/registry.cpp | 1 | ||||
-rw-r--r-- | libs/type_index/examples/runtime_cast.cpp | 90 | ||||
-rw-r--r-- | libs/type_index/examples/user_defined_typeinfo.hpp | 8 | ||||
-rw-r--r-- | libs/type_index/test/Jamfile.v2 | 1 | ||||
-rw-r--r-- | libs/type_index/test/type_index_constexpr_test.cpp | 1 | ||||
-rw-r--r-- | libs/type_index/test/type_index_runtime_cast_test.cpp | 296 | ||||
-rw-r--r-- | libs/type_index/test/type_index_test.cpp | 1 |
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 << 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< T ></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< U > const &</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<T> that points to an address suitably offset from u. If no such conversion exists, returns boost::shared_ptr<T>(); </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< T >::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 &</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& 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< const T >::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 &</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& 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<derived2*>(pb1)) { + assert(boost::typeindex::type_id_runtime(*pb1)) == boost::typeindex::type_id<derived2>()); +} +</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<derived2*>(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< T ></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< U > const &</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<T> that points to an address suitably offset from u. If no such conversion exists, returns std::shared_ptr<T>(); </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 &</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><boost/functional/hash.hpp> has to be included if this function is used. </para></note> +<note><para>Derived class header <emphasis role="bold">must</emphasis> include <boost/functional/hash.hpp>, <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>< Derived, TypeInfo > &</paramtype></parameter><description><para>This free function is used by Boost's unordered containers. <note><para><boost/functional/hash.hpp> 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> |