mirror of
https://github.com/boostorg/type_index.git
synced 2025-07-29 20:07:18 +02:00
Allow runtime type info even when RTTI is off. Improve tests and examples
This commit is contained in:
@ -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 <boost/type_index.hpp>
|
||||
#include <iostream>
|
||||
|
||||
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';
|
||||
|
@ -21,12 +21,13 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#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 <boost/type_index/stl_type_index.hpp>
|
||||
#else
|
||||
#else
|
||||
# include <boost/type_index/ctti_type_index.hpp>
|
||||
# include <boost/type_index/ctti_register_class.hpp>
|
||||
#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 <full/absolute/path/to/header/with/type_index>
|
||||
|
||||
|
||||
/// \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<C>() == 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 <class T>
|
||||
inline type_index type_id_runtime(const T* runtime_val) {
|
||||
return type_index::type_id_runtime(runtime_val);
|
||||
}
|
||||
|
||||
}} // namespace boost::typeind
|
||||
|
||||
|
||||
|
39
include/boost/type_index/ctti_register_class.hpp
Normal file
39
include/boost/type_index/ctti_register_class.hpp
Normal file
@ -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 <boost/type_index/ctti_type_index.hpp>
|
||||
|
||||
namespace boost { namespace typeind { namespace detail {
|
||||
|
||||
template <class T>
|
||||
inline const ctti_data& ctti_construct_typeid_ref(const T*) BOOST_NOEXCEPT {
|
||||
return ctti_construct<T>();
|
||||
}
|
||||
|
||||
}}} // 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
|
||||
|
@ -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 <class T>
|
||||
inline const ctti_data& ctti_construct() BOOST_NOEXCEPT {
|
||||
static const ctti_data result = { boost::detail::ctti<T>::n() };
|
||||
inline const detail::ctti_data& ctti_construct() BOOST_NOEXCEPT {
|
||||
static const detail::ctti_data result = { boost::detail::ctti<T>::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<void>())
|
||||
: data_(&ctti_construct<void>())
|
||||
{}
|
||||
|
||||
inline ctti_type_index(const type_info_t& data) BOOST_NOEXCEPT
|
||||
@ -78,9 +79,6 @@ public:
|
||||
template <class T>
|
||||
inline static ctti_type_index type_id_with_cvr() BOOST_NOEXCEPT;
|
||||
|
||||
template <class T>
|
||||
inline static ctti_type_index type_id_runtime(const T* variable) BOOST_NOEXCEPT;
|
||||
|
||||
template <class T>
|
||||
inline static ctti_type_index type_id_runtime(const T& variable) BOOST_NOEXCEPT;
|
||||
};
|
||||
@ -90,31 +88,20 @@ template <class T>
|
||||
inline ctti_type_index ctti_type_index::type_id() BOOST_NOEXCEPT {
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type no_ref_t;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::remove_cv<no_ref_t>::type no_cvr_t;
|
||||
return detail::ctti_construct<no_cvr_t>();
|
||||
return ctti_construct<no_cvr_t>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
inline ctti_type_index ctti_type_index::type_id_with_cvr() BOOST_NOEXCEPT {
|
||||
return detail::ctti_construct<T>();
|
||||
return ctti_construct<T>();
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
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<T>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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<T>();
|
||||
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
|
||||
|
||||
|
@ -110,9 +110,6 @@ public:
|
||||
template <class T>
|
||||
inline static stl_type_index type_id_with_cvr() BOOST_NOEXCEPT;
|
||||
|
||||
template <class T>
|
||||
inline static stl_type_index type_id_runtime(const T* variable);
|
||||
|
||||
template <class T>
|
||||
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 <class T>
|
||||
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 <class T>
|
||||
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);
|
||||
}
|
||||
|
@ -129,15 +129,6 @@ protected:
|
||||
template <class T>
|
||||
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 <class T>
|
||||
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.
|
||||
///
|
||||
|
@ -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/<link>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 : : : <rtti>off : registry_no_rtti ]
|
||||
[ run ../examples/exact_types_match.cpp : : : <rtti>off : exact_types_match_no_rtti ]
|
||||
[ run ../examples/demangled_names.cpp : : : <rtti>off : demangled_names_no_rtti ]
|
||||
[ compile-fail ../examples/inheritance.cpp : <rtti>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) : : : <rtti>off : $(target_name) ] ;
|
||||
}
|
||||
|
||||
|
@ -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<C>(), 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<B>(), 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;
|
||||
|
Reference in New Issue
Block a user