diff --git a/doc/type_index.qbk b/doc/type_index.qbk index 6800b7e..4dc531f 100644 --- a/doc/type_index.qbk +++ b/doc/type_index.qbk @@ -33,7 +33,7 @@ Boost.TypeIndex library was designed to work around all those issues. [classref boost::typeindex::type_info boost::typeindex::type_info] is a drop-in replacement for `std::type_info` and [classref boost::typeindex::type_index boost::typeindex::type_index] -is a drop-in replacement for `std::type_index`. Unlike Standard Library versions those classes may work without RTTI. +is a drop-in replacement for `std::type_index`. Unlike Standard Library versions those classes can work without RTTI. `type_index` provides the full set of comparison operators, hashing functions and ostream operators, so it can be used with any container class. @@ -228,7 +228,7 @@ Issues with cross module type comparison on a bugged compilers are bypassed by d [section Getting through the inheritance to receive a real type name ] [type_index_derived_example] [endsect] [import ../examples/exact_types_match.cpp] -[section Exact type match: storing type with const, volatile and reference ] [type_index_exact_type_match_example] [endsect] +[section Exact type matching: storing type with const, volatile and reference qualifiers] [type_index_exact_type_match_example] [endsect] [import ../examples/table_of_names.cpp] [section Table of raw_name() and pretty_name() outputs with and without RTTI ] [type_index_names_table] [endsect] @@ -354,7 +354,7 @@ and `BOOST_TYPE_INDEX_CTTI_END_SKIP` to `sizeof(">::n(void)") - 1`. Linking a binary from source files that were compiled with different RTTI flags is not a very good idea and may lead to a lot of surprises. However if there is a very strong need, TypeIndex library -provides a solution for mixing sources: just define `BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY` +provides a solution for mixing sources: just define [macroref BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY] macro. This would lead to usage of same type_index class (`boost::typeindex::ctti_type_index` or `boost::typeindex::stl_type_index`) all around the project. diff --git a/examples/exact_types_match.cpp b/examples/exact_types_match.cpp index 7521bf5..f5d0115 100644 --- a/examples/exact_types_match.cpp +++ b/examples/exact_types_match.cpp @@ -9,9 +9,9 @@ The following example shows that `type_index` (and `type_info`) is able to store the exact type, without stripping const, volatile and references. Example works with and without RTTI. - In this example we'll create a class, that stores pointer to function and remembers the exact type of a - parameter that function accepts. When an attempt to call the stored function will be made, type of input - parameter will be checked for exact match with initially erased type of function. + In this example we'll create a class that stores a pointer to function and remembers the exact type of the + parameter the function accepts. When the call to the bound function is made, he actual input parameter + type is checked against the stored parameter type and an exception is thrown in case of mismatch. */ #include @@ -20,8 +20,8 @@ #include class type_erased_unary_function { - void* function_ptr_; - boost::typeindex::type_index exact_param_t_; + void* function_ptr_; + boost::typeindex::type_index exact_param_t_; public: template diff --git a/include/boost/type_index.hpp b/include/boost/type_index.hpp index b3f917b..030e3b3 100644 --- a/include/boost/type_index.hpp +++ b/include/boost/type_index.hpp @@ -14,11 +14,6 @@ /// By inclusion of this file most optimal type index classes will be included and used /// as a boost::typeindex::type_index and boost::typeindex::type_info. -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) -# pragma once -#endif - #include #if defined(BOOST_TYPE_INDEX_USER_TYPEINDEX) @@ -33,6 +28,10 @@ # include #endif +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + namespace boost { namespace typeindex { #if defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED) @@ -82,7 +81,7 @@ typedef type_index::type_info_t type_info; /// Put this macro into the public section of polymorphic class to allow runtime type detection. /// /// Depending on the typeid() availability this macro will expand to nothing or to virtual helper function -/// `virtual const type_info& type_id_runtime() const`. +/// `virtual const type_info& boost_type_info_type_id_runtime_() const noexcept`. /// /// \b Example: /// \code diff --git a/include/boost/type_index/ctti_register_class.hpp b/include/boost/type_index/ctti_register_class.hpp index 2a30571..cd9dc8e 100644 --- a/include/boost/type_index/ctti_register_class.hpp +++ b/include/boost/type_index/ctti_register_class.hpp @@ -9,16 +9,15 @@ #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 +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + namespace boost { namespace typeindex { namespace detail { template @@ -33,11 +32,11 @@ inline const ctti_data& ctti_construct_typeid_ref(const T*) BOOST_NOEXCEPT { /// and `typeid()` does not work. /// /// BOOST_TYPE_INDEX_REGISTER_CTTI_CLASS macro expands to declaration and implementation of -/// `virtual const detail::ctti_data& type_id_runtime() const` method. -#define BOOST_TYPE_INDEX_REGISTER_CTTI_CLASS \ - virtual const boost::typeindex::detail::ctti_data& type_id_runtime() const BOOST_NOEXCEPT { \ - return boost::typeindex::detail::ctti_construct_typeid_ref(this); \ - } \ +/// `virtual const type_info& boost_type_info_type_id_runtime_() const noexcept` method. +#define BOOST_TYPE_INDEX_REGISTER_CTTI_CLASS \ + virtual const boost::typeindex::detail::ctti_data& boost_type_index_type_id_runtime_() const BOOST_NOEXCEPT { \ + return boost::typeindex::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 120514f..9bafae7 100644 --- a/include/boost/type_index/ctti_type_index.hpp +++ b/include/boost/type_index/ctti_type_index.hpp @@ -9,11 +9,6 @@ #ifndef BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_HPP #define BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) -# pragma once -#endif - /// \file ctti_type_index.hpp /// \brief Contains boost::typeindex::ctti_type_index class. /// @@ -31,6 +26,10 @@ #include #include +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + namespace boost { namespace typeindex { namespace detail { @@ -42,12 +41,33 @@ namespace detail { // 4) we need a compile-time control to make shure that user does not copy or // default construct `struct-that-represents-type` // -// Solution would be a standard-layout class with private constructors and assignment operators. +// Solution would be the following: + +/// \class ctti_data +/// Standard-layout class with private constructors and assignment operators. +/// +/// You can not work with this class directly. The purpose of this class is to hold type info +/// \b when \b RTTI \b is \b off and allow ctti_type_index construction from itself. +/// +/// \b Example: +/// \code +/// const detail::ctti_data& foo(); +/// ... +/// type_index ti = type_index(foo()); +/// std::cout << ti.pretty_name(); +/// \endcode class ctti_data { +#ifndef BOOST_NO_CXX11_DELETED_FUNCTIONS +public: + ctti_data() = delete; + ctti_data(const ctti_data&) = delete; + ctti_data& operator=(const ctti_data&) = delete; +#else private: ctti_data(); ctti_data(const ctti_data&); ctti_data& operator=(const ctti_data&); +#endif }; } // namespace detail @@ -77,6 +97,10 @@ inline const detail::ctti_data& ctti_construct() BOOST_NOEXCEPT { class ctti_type_index: public type_index_facade { const detail::ctti_data* data_; + inline std::size_t get_raw_name_length() const BOOST_NOEXCEPT { + return std::strlen(raw_name() + detail::ctti_skip_size_at_end); + } + public: typedef detail::ctti_data type_info_t; @@ -126,7 +150,7 @@ inline ctti_type_index ctti_type_index::type_id_with_cvr() BOOST_NOEXCEPT { template inline ctti_type_index ctti_type_index::type_id_runtime(const T& variable) BOOST_NOEXCEPT { - return variable.type_id_runtime(); + return variable.boost_type_index_type_id_runtime_(); } @@ -136,14 +160,14 @@ inline const char* ctti_type_index::raw_name() const BOOST_NOEXCEPT { inline std::string ctti_type_index::pretty_name() const { - std::size_t len = std::strlen(raw_name() + detail::ctti_skip_size_at_end); + std::size_t len = get_raw_name_length(); while (raw_name()[len - 1] == ' ') --len; // MSVC sometimes adds whitespaces return std::string(raw_name(), len); } inline std::size_t ctti_type_index::hash_code() const BOOST_NOEXCEPT { - return boost::hash_range(raw_name(), raw_name() + std::strlen(raw_name() + detail::ctti_skip_size_at_end)); + return boost::hash_range(raw_name(), raw_name() + get_raw_name_length()); } diff --git a/include/boost/type_index/stl_register_class.hpp b/include/boost/type_index/stl_register_class.hpp index 6bbd180..8855775 100644 --- a/include/boost/type_index/stl_register_class.hpp +++ b/include/boost/type_index/stl_register_class.hpp @@ -9,16 +9,15 @@ #ifndef BOOST_TYPE_INDEX_STL_REGISTER_CLASS_HPP #define BOOST_TYPE_INDEX_STL_REGISTER_CLASS_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) -# pragma once -#endif - /// \file stl_register_class.hpp /// \brief Contains BOOST_TYPE_INDEX_REGISTER_STL_CLASS macro. #include +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + namespace boost { namespace typeindex { namespace detail { template @@ -34,11 +33,11 @@ inline const stl_type_index::type_info_t& stl_construct_typeid_ref(const T*) BOO /// and `typeid()` does work. /// /// BOOST_TYPE_INDEX_REGISTER_STL_CLASS macro expands to declaration and implementation of -/// `virtual const std::type_info& type_id_runtime() const` method. -#define BOOST_TYPE_INDEX_REGISTER_STL_CLASS \ - virtual const boost::typeindex::stl_type_index::type_info_t& type_id_runtime() const BOOST_NOEXCEPT { \ - return boost::typeindex::detail::stl_construct_typeid_ref(this); \ - } \ +/// `virtual const type_info& boost_type_info_type_id_runtime_() const noexcept` method. +#define BOOST_TYPE_INDEX_REGISTER_STL_CLASS \ + virtual const boost::typeindex::stl_type_index::type_info_t& boost_type_index_type_id_runtime_() const BOOST_NOEXCEPT { \ + return boost::typeindex::detail::stl_construct_typeid_ref(this); \ + } \ /**/ #endif // BOOST_TYPE_INDEX_STL_REGISTER_CLASS_HPP diff --git a/include/boost/type_index/stl_type_index.hpp b/include/boost/type_index/stl_type_index.hpp index 25a77f6..807dcb0 100644 --- a/include/boost/type_index/stl_type_index.hpp +++ b/include/boost/type_index/stl_type_index.hpp @@ -9,11 +9,6 @@ #ifndef BOOST_TYPE_INDEX_STL_TYPE_INDEX_HPP #define BOOST_TYPE_INDEX_STL_TYPE_INDEX_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) -# pragma once -#endif - /// \file stl_type_index.hpp /// \brief Contains boost::typeindex::stl_type_index class. /// @@ -26,7 +21,6 @@ #include - // MSVC is capable of calling typeid(T) even when RTTI is off #if defined(BOOST_NO_RTTI) && !defined(BOOST_MSVC) #error "File boost/type_index/stl_type_index.ipp is not usable when typeid() is not available." @@ -41,6 +35,7 @@ #include #include #include +#include #include @@ -51,6 +46,7 @@ #if !defined(BOOST_MSVC) # include # include +# include // std::free #endif #if (defined(__EDG_VERSION__) && __EDG_VERSION__ < 245) \ @@ -58,6 +54,10 @@ # include #endif +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + namespace boost { namespace typeindex { /// \class stl_type_index @@ -143,11 +143,11 @@ inline std::string stl_type_index::pretty_name() const { BOOST_TRY { ret = demang; // may throw out of memory exception } BOOST_CATCH (...) { - free(demang); + std::free(demang); BOOST_RETHROW; } BOOST_CATCH_END - free(demang); + std::free(demang); #endif std::string::size_type pos = ret.find("boost::typeindex::detail::cvr_saver<"); @@ -234,10 +234,8 @@ namespace detail { template inline stl_type_index stl_type_index::type_id_with_cvr() BOOST_NOEXCEPT { - typedef typename boost::mpl::if_c< - boost::is_reference::value - || boost::is_const::value - || boost::is_volatile::value, + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_< + boost::mpl::or_, boost::is_const, boost::is_volatile >, detail::cvr_saver, T >::type type; @@ -249,7 +247,7 @@ inline stl_type_index stl_type_index::type_id_with_cvr() BOOST_NOEXCEPT { template inline stl_type_index stl_type_index::type_id_runtime(const T& value) BOOST_NOEXCEPT { #ifdef BOOST_NO_RTTI - return value.type_id_runtime(); + return value.boost_type_index_type_id_runtime_(); #else return typeid(value); #endif diff --git a/include/boost/type_index/type_index_facade.hpp b/include/boost/type_index/type_index_facade.hpp index dcb4841..f050e73 100644 --- a/include/boost/type_index/type_index_facade.hpp +++ b/include/boost/type_index/type_index_facade.hpp @@ -9,11 +9,6 @@ #ifndef BOOST_TYPE_INDEX_TYPE_INDEX_FACADE_HPP #define BOOST_TYPE_INDEX_TYPE_INDEX_FACADE_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) -# pragma once -#endif - #include #include #include @@ -27,6 +22,10 @@ #endif #endif +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + namespace boost { namespace typeindex { /// \class type_index_facade @@ -65,46 +64,50 @@ private: public: typedef TypeInfo type_info_t; +#if defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED) /// \b Override: This function \b must be redefined in Derived class. Overrides \b must not throw. /// \return Const reference to underlying low level type_info_t. - inline const type_info_t& type_info() const BOOST_NOEXCEPT { - return derived().type_info(); - } + inline const type_info_t& type_info() const BOOST_NOEXCEPT; /// \b Override: This function \b must be redefined in Derived class. Overrides \b must not throw. /// \return Pointer to unredable/raw type name. - inline const char* raw_name() const BOOST_NOEXCEPT { + inline const char* raw_name() const BOOST_NOEXCEPT; +#endif + + /// \b Override: This function \b may be redefined in Derived class. Overrides \b must not throw. + /// \return Name of a type. By default retuns Derived::raw_name(). + inline const char* name() const BOOST_NOEXCEPT { return derived().raw_name(); } - /// \b Override: This function \b must be redefined in Derived class. Overrides may throw. - /// \return Human redable type name. + /// \b Override: This function \b may be redefined in Derived class. Overrides may throw. + /// \return Human redable type name. By default retuns Derived::name(). inline std::string pretty_name() const { - return derived().pretty_name(); - } - - /// \b Override: This function \b may be redefined in Derived class. Overrides \b must not throw. - /// \return Name of a type. By default retuns raw_name(). - inline const char* name() const BOOST_NOEXCEPT { - return raw_name(); + return derived().name(); } /// \b Override: This function \b may be redefined in Derived class. Overrides \b must not throw. /// \return True if two types are equal. By default compares types by raw_name(). inline bool equal(const Derived& rhs) const BOOST_NOEXCEPT { - return raw_name() == rhs.raw_name() || !std::strcmp(raw_name(), rhs.raw_name()); + const char* const left = derived().raw_name(); + const char* const right = rhs.raw_name(); + return left == right || !std::strcmp(left, right); } /// \b Override: This function \b may be redefined in Derived class. Overrides \b must not throw. /// \return True if rhs is greater than this. By default compares types by raw_name(). inline bool before(const Derived& rhs) const BOOST_NOEXCEPT { - return raw_name() != rhs.raw_name() && std::strcmp(raw_name(), rhs.raw_name()) < 0; + const char* const left = derived().raw_name(); + const char* const right = rhs.raw_name(); + return left != right && std::strcmp(left, right) < 0; } /// \b Override: This function \b may be redefined in Derived class. Overrides \b must not throw. /// \return Hash code of a type. By default hashes types by raw_name(). + /// \note has to be included if this function is used. inline std::size_t hash_code() const BOOST_NOEXCEPT { - return boost::hash_range(raw_name(), raw_name() + std::strlen(raw_name())); + const char* const name = derived().raw_name(); + return boost::hash_range(name, name + std::strlen(name)); } #if defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED) @@ -260,7 +263,7 @@ bool operator ==, !=, <, ... (const TypeInfo& lhs, const type_index_facade& rhs) /// Ostream operator that will output demangled name template inline std::ostream& operator<<(std::ostream& ostr, const type_index_facade& ind) { - ostr << ind.pretty_name(); + ostr << static_cast(ind).pretty_name(); return ostr; } /// @endcond @@ -271,13 +274,14 @@ inline std::basic_ostream& operator<<( std::basic_ostream& ostr, const type_index_facade& ind) { - ostr << ind.pretty_name(); + ostr << static_cast(ind).pretty_name(); return ostr; } #endif // BOOST_NO_TEMPLATED_IOSTREAMS #endif // BOOST_NO_IOSTREAM /// This free function is used by Boost's unordered containers. +/// \note has to be included if this function is used. template inline std::size_t hash_value(const type_index_facade& lhs) BOOST_NOEXCEPT { return static_cast(lhs).hash_code(); diff --git a/test/type_index_test.cpp b/test/type_index_test.cpp index 7f5ede0..45cbf09 100644 --- a/test/type_index_test.cpp +++ b/test/type_index_test.cpp @@ -297,7 +297,7 @@ BOOST_AUTO_TEST_CASE(comparators_type_id_runtime) BOOST_CHECK(typeid(&rc1) == typeid(pb1)); BOOST_CHECK(typeid(&rb1) == typeid(pc1)); #else - BOOST_CHECK(boost::typeindex::type_index(pc1->type_id_runtime()).raw_name()); + BOOST_CHECK(boost::typeindex::type_index(pc1->boost_type_index_type_id_runtime_()).raw_name()); #endif BOOST_CHECK_EQUAL(boost::typeindex::type_id_runtime(rc1), boost::typeindex::type_id_runtime(*pc1));