diff --git a/examples/inheritance.cpp b/examples/inheritance.cpp index 342e2ab..0e7b3a7 100644 --- a/examples/inheritance.cpp +++ b/examples/inheritance.cpp @@ -9,16 +9,18 @@ The following example shows that `boost::type_info` is able to store the real type, successfully getting through all the inheritances. - Example works with RTTI only. Without RTTI support it won't compile, producing a compile-time error with message: - "boost::type_id_rtti_only(T&) requires RTTI" + Example works with and without RTTI." */ #include #include -struct A { virtual ~A(){} }; -struct B: public A {}; -struct C: public B {}; +struct A { + BOOST_TYPE_INDEX_REGISTER_CLASS + virtual ~A(){} +}; +struct B: public A { BOOST_TYPE_INDEX_REGISTER_CLASS }; +struct C: public B { BOOST_TYPE_INDEX_REGISTER_CLASS }; void print_real_type(const A& a) { std::cout << boost::typeind::type_id_runtime(a).pretty_name() << '\n'; diff --git a/include/boost/type_index.hpp b/include/boost/type_index.hpp index ecea183..601534c 100644 --- a/include/boost/type_index.hpp +++ b/include/boost/type_index.hpp @@ -21,12 +21,13 @@ #include -#if defined(BOOST_TYPE_INDEX_USER_TYPEINDEX) && defined(BOOST_TYPE_INDEX_USER_TYPEINDEX_NAME) +#if defined(BOOST_TYPE_INDEX_USER_TYPEINDEX) # include BOOST_TYPE_INDEX_USER_TYPEINDEX #elif (!defined(BOOST_NO_RTTI) && !defined(BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY)) || defined(BOOST_MSVC) # include -#else +#else # include +# include #endif namespace boost { namespace typeind { @@ -38,12 +39,14 @@ namespace boost { namespace typeind { /// Could be a boost::typeind::stl_type_index, boost::typeind::ctti_type_index or /// user defined type_index class. typedef platform-specific type_index; -#elif defined(BOOST_TYPE_INDEX_USER_TYPEINDEX) && defined(BOOST_TYPE_INDEX_USER_TYPEINDEX_NAME) - typedef BOOST_TYPE_INDEX_USER_TYPEINDEX_NAME type_index; +#elif defined(BOOST_TYPE_INDEX_USER_TYPEINDEX) + // Nothing to do #elif (!defined(BOOST_NO_RTTI) && !defined(BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY)) || defined(BOOST_MSVC) typedef boost::typeind::stl_type_index type_index; +# define BOOST_TYPE_INDEX_REGISTER_CLASS #else typedef boost::typeind::ctti_type_index type_index; +# define BOOST_TYPE_INDEX_REGISTER_CLASS BOOST_TYPE_INDEX_REGISTER_CTTI_CLASS #endif /// Depending on a compiler flags, optimal implementation of type_info will be used @@ -58,17 +61,35 @@ typedef type_index::type_info_t type_info; /// \def BOOST_TYPE_INDEX_USER_TYPEINFO /// BOOST_TYPE_INDEX_USER_TYPEINFO can be defined to the path to header file /// with user provided implementation of type_index. -/// -/// BOOST_TYPE_INDEX_USER_TYPEINDEX_NAME must be also defined! #define BOOST_TYPE_INDEX_USER_TYPEINDEX -/// \def BOOST_TYPE_INDEX_USER_TYPEINDEX_NAME -/// BOOST_TYPE_INDEX_USER_TYPEINDEX_NAME can be defined to the fullty -/// qualified name of the user's type_index implementation. +/// \def BOOST_TYPE_INDEX_REGISTER_CLASS +/// BOOST_TYPE_INDEX_REGISTER_CLASS is a helper macro that is used to help to emulate RTTI. +/// Put this macro into the public section of polymorphic class to allow runtime type detection. +/// \b Example: +/// \code +/// class A { +/// public: +/// BOOST_TYPE_INDEX_REGISTER_CLASS +/// virtual ~A(){} +/// }; /// -/// BOOST_TYPE_INDEX_USER_TYPEINDEX must be also defined! -#define BOOST_TYPE_INDEX_USER_TYPEINDEX_NAME my_namespace::my_type_index +/// struct B: public A { +/// BOOST_TYPE_INDEX_REGISTER_CLASS +/// }; +/// +/// struct C: public B { +/// BOOST_TYPE_INDEX_REGISTER_CLASS +/// }; +/// +/// ... +/// +/// C c1; +/// A* pc1 = &c1; +/// assert(boost::typeind::type_id() == boost::typeind::type_id_runtime(*pc1)); +/// \endcode +#define BOOST_TYPE_INDEX_REGISTER_CLASS nothing-or-some-virtual-functions #endif // defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED) @@ -136,31 +157,6 @@ inline type_index type_id_runtime(const T& runtime_val) BOOST_NOEXCEPT { return type_index::type_id_runtime(runtime_val); } -/// Function that works exactly like C++ typeid(rtti_val) call, but returns boost::type_index. -/// -/// Retunrs runtime information about specified type. -/// -/// \b Requirements: RTTI available or specially designed user type_info class must be provided -/// via BOOST_TYPE_INDEX_USER_TYPEINDEX and BOOST_TYPE_INDEX_USER_TYPEINDEX_NAME macro. -/// -/// \b Example: -/// \code -/// struct Base { virtual ~Base(){} }; -/// struct Derived: public Base {}; -/// ... -/// Base* b = new Derived(); -/// type_index ti = type_id_runtime(b); -/// std::cout << ti.pretty_name(); // Outputs 'Derived*' -/// \endcode -/// -/// \param runtime_val Varaible which runtime type must be returned. -/// \throw Nothing. -/// \return boost::typeind::type_index with information about the specified variable. -template -inline type_index type_id_runtime(const T* runtime_val) { - return type_index::type_id_runtime(runtime_val); -} - }} // namespace boost::typeind diff --git a/include/boost/type_index/ctti_register_class.hpp b/include/boost/type_index/ctti_register_class.hpp new file mode 100644 index 0000000..23ac6e8 --- /dev/null +++ b/include/boost/type_index/ctti_register_class.hpp @@ -0,0 +1,39 @@ +// +// Copyright (c) Antony Polukhin, 2013-2014. +// +// +// 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) +// + +#ifndef BOOST_TYPE_INDEX_CTTI_REGISTER_CLASS_HPP +#define BOOST_TYPE_INDEX_CTTI_REGISTER_CLASS_HPP + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) +# pragma once +#endif + +/// \file ctti_register_class.hpp +/// \brief Contains BOOST_TYPE_INDEX_REGISTER_CTTI_CLASS macro. + +#include + +namespace boost { namespace typeind { namespace detail { + +template +inline const ctti_data& ctti_construct_typeid_ref(const T*) BOOST_NOEXCEPT { + return ctti_construct(); +} + +}}} // namespace boost::typeind::detail + + +#define BOOST_TYPE_INDEX_REGISTER_CTTI_CLASS \ + virtual const boost::typeind::detail::ctti_data& type_id_ref() const BOOST_NOEXCEPT { \ + return boost::typeind::detail::ctti_construct_typeid_ref(this); \ + } \ +/**/ + +#endif // BOOST_TYPE_INDEX_CTTI_REGISTER_CLASS_HPP + diff --git a/include/boost/type_index/ctti_type_index.hpp b/include/boost/type_index/ctti_type_index.hpp index cdf0728..b7110b5 100644 --- a/include/boost/type_index/ctti_type_index.hpp +++ b/include/boost/type_index/ctti_type_index.hpp @@ -39,14 +39,15 @@ struct ctti_data { const char* typename_; }; +} // namespace detail + +/// Helper method for getting detail::ctti_data of a tempalte patameter T. template -inline const ctti_data& ctti_construct() BOOST_NOEXCEPT { - static const ctti_data result = { boost::detail::ctti::n() }; +inline const detail::ctti_data& ctti_construct() BOOST_NOEXCEPT { + static const detail::ctti_data result = { boost::detail::ctti::n() }; return result; } -} // namespace detail - /// \class ctti_type_index /// This class is a wrapper that pretends to work exactly like stl_type_info, but does /// not require RTTI support. For description of functions see type_index_facade. @@ -60,7 +61,7 @@ public: typedef detail::ctti_data type_info_t; inline ctti_type_index() BOOST_NOEXCEPT - : data_(&detail::ctti_construct()) + : data_(&ctti_construct()) {} inline ctti_type_index(const type_info_t& data) BOOST_NOEXCEPT @@ -78,9 +79,6 @@ public: template inline static ctti_type_index type_id_with_cvr() BOOST_NOEXCEPT; - template - inline static ctti_type_index type_id_runtime(const T* variable) BOOST_NOEXCEPT; - template inline static ctti_type_index type_id_runtime(const T& variable) BOOST_NOEXCEPT; }; @@ -90,31 +88,20 @@ template inline ctti_type_index ctti_type_index::type_id() BOOST_NOEXCEPT { typedef BOOST_DEDUCED_TYPENAME boost::remove_reference::type no_ref_t; typedef BOOST_DEDUCED_TYPENAME boost::remove_cv::type no_cvr_t; - return detail::ctti_construct(); + return ctti_construct(); } template inline ctti_type_index ctti_type_index::type_id_with_cvr() BOOST_NOEXCEPT { - return detail::ctti_construct(); + return ctti_construct(); } template -inline ctti_type_index ctti_type_index::type_id_runtime(const T* rtti_val) BOOST_NOEXCEPT { - BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, - "type_id_runtime(const T*) and type_index::construct_runtime(const T*) require RTTI"); - - return detail::ctti_construct(); -} - -template -inline ctti_type_index ctti_type_index::type_id_runtime(const T& rtti_val) BOOST_NOEXCEPT { - BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, - "type_id_runtime(const T&) and type_index::construct_runtime(const T&) require RTTI"); - - return detail::ctti_construct(); +inline ctti_type_index ctti_type_index::type_id_runtime(const T& variable) BOOST_NOEXCEPT { + return variable.type_id_ref(); } @@ -137,6 +124,5 @@ inline std::size_t ctti_type_index::hash_code() const BOOST_NOEXCEPT { }} // namespace boost::typeind - -#endif // BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_IPP +#endif // BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_HPP diff --git a/include/boost/type_index/stl_type_index.hpp b/include/boost/type_index/stl_type_index.hpp index a5f9a0b..26e99e7 100644 --- a/include/boost/type_index/stl_type_index.hpp +++ b/include/boost/type_index/stl_type_index.hpp @@ -110,9 +110,6 @@ public: template inline static stl_type_index type_id_with_cvr() BOOST_NOEXCEPT; - template - inline static stl_type_index type_id_runtime(const T* variable); - template inline static stl_type_index type_id_runtime(const T& value) BOOST_NOEXCEPT; }; @@ -248,20 +245,12 @@ inline stl_type_index stl_type_index::type_id_with_cvr() BOOST_NOEXCEPT { return typeid(type); } -template -inline stl_type_index stl_type_index::type_id_runtime(const T* rtti_val) { -#ifdef BOOST_NO_RTTI - BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, - "type_id_runtime(const T*) and type_index::construct_runtime(const T*) require RTTI"); -#endif - return typeid(rtti_val); -} template inline stl_type_index stl_type_index::type_id_runtime(const T& value) BOOST_NOEXCEPT { #ifdef BOOST_NO_RTTI BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, - "type_id_runtime(const T&) and type_index::construct_runtime(const T&) require RTTI"); + "stl_type_index::type_id_runtime(const T&) require RTTI"); #endif return typeid(value); } diff --git a/include/boost/type_index/type_index_facade.hpp b/include/boost/type_index/type_index_facade.hpp index 89f060a..aa70517 100644 --- a/include/boost/type_index/type_index_facade.hpp +++ b/include/boost/type_index/type_index_facade.hpp @@ -129,15 +129,6 @@ protected: template static Derived type_id_with_cvr() BOOST_NOEXCEPT; - /// This is a factory method that is used to create instances of Derived classes. - /// boost::typeind::type_id_runtime(const T*) will call this method, if Derived has same type as boost::typeind::type_index. - /// - /// \b Override: This function \b may be redefined and made public in Derived class. - /// \param variable Variable which runtime type will be stored in type_index. - /// \return type_index with runtime type of variable. - template - static Derived type_id_runtime(const T* variable); - /// This is a factory method that is used to create instances of Derived classes. /// boost::typeind::type_id_runtime(const T&) will call this method, if Derived has same type as boost::typeind::type_index. /// diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 937b1b4..e690b6c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -6,7 +6,7 @@ import testing ; import feature ; - +import os ; # Variable that contains all the stuff required for linking against -lboost_unit_test tlib = /boost/test//boost_unit_test_framework/static ; @@ -45,17 +45,16 @@ test-suite type_index #[ link-fail testing_crossmodule.cpp $(tlib) test_lib_nortti : : link_fail_rtti_nortti ] [ run testing_crossmodule.cpp $(tlib) test_lib_rtti_compat : : : $(nortti) $(compat) : testing_crossmodule_nortti_rtti_compat ] [ run testing_crossmodule.cpp $(tlib) test_lib_nortti_compat : : : $(compat) : testing_crossmodule_rtti_nortti_compat ] - - # Examples that must work even with RTTI disabled - [ run ../examples/registry.cpp : : : off : registry_no_rtti ] - [ run ../examples/exact_types_match.cpp : : : off : exact_types_match_no_rtti ] - [ run ../examples/demangled_names.cpp : : : off : demangled_names_no_rtti ] - [ compile-fail ../examples/inheritance.cpp : off : failing_inheritance_example ] ; # Assuring that examples compile and run. Adding sources from `examples` directory to the `type_index` test suite. for local p in [ glob ../examples/*.cpp ] { + # RTTI on type_index += [ run $(p) ] ; + + # RTTI off + local target_name = $(p[1]:B)_no_rtti ; + type_index += [ run $(p) : : : off : $(target_name) ] ; } diff --git a/test/type_index_test.cpp b/test/type_index_test.cpp index cf05730..95a55d9 100644 --- a/test/type_index_test.cpp +++ b/test/type_index_test.cpp @@ -245,11 +245,19 @@ BOOST_AUTO_TEST_CASE(type_index_user_defined_class_test) } -#ifndef BOOST_NO_RTTI +struct A { +public: + BOOST_TYPE_INDEX_REGISTER_CLASS + virtual ~A(){} +}; -class A { public: virtual ~A(){} }; -class B: public A{}; -class C: public B {}; +struct B: public A { + BOOST_TYPE_INDEX_REGISTER_CLASS +}; + +struct C: public B { + BOOST_TYPE_INDEX_REGISTER_CLASS +}; BOOST_AUTO_TEST_CASE(comparators_type_id_runtime) { @@ -259,6 +267,8 @@ BOOST_AUTO_TEST_CASE(comparators_type_id_runtime) A& rc1 = c1; A* pb1 = &b1; A& rb1 = b1; + +#ifndef BOOST_NO_RTTI BOOST_CHECK(typeid(rc1) == typeid(*pc1)); BOOST_CHECK(typeid(rb1) == typeid(*pb1)); @@ -267,12 +277,19 @@ BOOST_AUTO_TEST_CASE(comparators_type_id_runtime) BOOST_CHECK(typeid(&rc1) == typeid(pb1)); BOOST_CHECK(typeid(&rb1) == typeid(pc1)); +#else + BOOST_CHECK(boost::typeind::type_index(pc1->type_id_ref()).raw_name()); +#endif BOOST_CHECK_EQUAL(boost::typeind::type_id_runtime(rc1), boost::typeind::type_id_runtime(*pc1)); + BOOST_CHECK_EQUAL(boost::typeind::type_id(), boost::typeind::type_id_runtime(*pc1)); BOOST_CHECK_EQUAL(boost::typeind::type_id_runtime(rb1), boost::typeind::type_id_runtime(*pb1)); + BOOST_CHECK_EQUAL(boost::typeind::type_id(), boost::typeind::type_id_runtime(*pb1)); BOOST_CHECK_NE(boost::typeind::type_id_runtime(rc1), boost::typeind::type_id_runtime(*pb1)); BOOST_CHECK_NE(boost::typeind::type_id_runtime(rb1), boost::typeind::type_id_runtime(*pc1)); + +#ifndef BOOST_NO_RTTI BOOST_CHECK_EQUAL(boost::typeind::type_id_runtime(&rc1), boost::typeind::type_id_runtime(pb1)); BOOST_CHECK_EQUAL(boost::typeind::type_id_runtime(&rb1), boost::typeind::type_id_runtime(pc1)); @@ -283,9 +300,12 @@ BOOST_AUTO_TEST_CASE(comparators_type_id_runtime) BOOST_CHECK(boost::typeind::type_id_runtime(rb1) != typeid(*pc1)); BOOST_CHECK(boost::typeind::type_id_runtime(&rc1) == typeid(pb1)); BOOST_CHECK(boost::typeind::type_id_runtime(&rb1) == typeid(pc1)); +#endif } +#ifndef BOOST_NO_RTTI + BOOST_AUTO_TEST_CASE(comparators_type_id_vs_type_info) { using namespace boost::typeind;