Note: This paper is a very early draft just to stir conversation.
1. Introduction
The standard library class,
, is useful in its current
form however it is lacking some vital information. The addition of a
member function
would return a pair of iterators
to the
for all the base classes.
class type_info_iterator { public : type_info const & operator * ( void ) const noexcept ; type_info const * operator -> ( void ) const noexcept ; type_info_iterator & operator ++ ( void ) noexcept ; ptrdiff_t operator - ( type_info_iterator const & rhs ) noexcept ; bool operator != ( type_info_iterator const & rhs ) const noexcept ; }; class type_info { public : bool is_polymorphic () const noexcept ; pair < type_info_iterator , type_info_iterator > bases ( void ) const noexcept ; };
2. Possible implementation
2.1. GNU g++, LLVM clang, Intel ICX
#include <typeinfo>// type_info #include <utility>// pair #include <cxxabi.h>// __cxxabiv1::__base_class_type_info class type_info_iterator { friend class type_info ; __cxxabiv1 :: __base_class_type_info const * p ; public : type_info const & operator * ( void ) const noexcept { return * p -> __base_type ; } type_info const * operator -> ( void ) const noexcept { return &** this ; } type_info_iterator & operator ++ ( void ) noexcept { ++ p ; return * this ; } size_t operator - ( type_info_iterator const & rhs ) noexcept { return this -> p - rhs . p ; } bool operator != ( type_info_iterator const & rhs ) const noexcept { return this -> p != rhs . p ; } }; pair < type_info_iterator , type_info_iterator > type_info :: bases ( type_info const & ti ) const noexcept { using namespace __cxxabiv1 ; auto const * const c = dynamic_cast < __class_type_info const *> ( & ti ); if ( nullptr == c ) return {}; auto const * const sic = dynamic_cast < __si_class_type_info const *> ( & ti ); if ( nullptr != sic ) { pair < type_info_iterator , type_info_iterator > retval ; auto const * const q = ( __cxxabiv1 :: __base_class_type_info * ) sic -> __base_type ; retval . first . p = q ; retval . second . p = q + 1 ; return retval ; } auto const * const vmi = dynamic_cast < __vmi_class_type_info const *> ( & ti ); if ( nullptr != vmi ) { pair < type_info_iterator , type_info_iterator > retval ; retval . first . p = vmi -> __base_info ; retval . second . p = vmi -> __base_info + vmi -> __base_count ; return retval ; } return {}; }
2.2. Microsoft Visual C++
#include <cassert>// assert #include <typeinfo>// type_info #include <utility>// pair #include <rttidata.h>// _RTTICompleteObjectLocator, _RTTIClassHierarchyDescriptor using std :: pair , std :: type_info ; _RTTICompleteObjectLocator const * type_info_to_locator ( type_info const * const pti ) noexcept { using std :: int32_t , std :: uintptr_t ; // Just in case 'pti' is an unaligned // address, subtract bytes to align it uintptr_t addr = reinterpret_cast < uintptr_t > ( static_cast < void const *> ( pti )); addr -= addr % alignof ( uint32_t ); // Now we have an aligned address int32_t const * p = static_cast < int32_t *> ( reinterpret_cast < void *> ( addr )); for ( -- p ; ; -- p ) { // If we have found the _RTTICompleteObjectLocator, // the pointer is pointing to its last element, // so we subtract 20 bytes to bring the pointer // to the beginning of the _RTTICompleteObjectLocator _RTTICompleteObjectLocator const & locator = * ( _RTTICompleteObjectLocator * )( p - 5 ); char const * const base = ( char * ) & locator - locator . pSelf ; // If we have found the _RTTICompleteObjectLocator, // we can calculate where we expect the type_info // to be located at: char const * const p_expected_type_info = base + locator . pTypeDescriptor ; // Now let's see if we've really found it if ( ( char * ) pti != p_expected_type_info ) continue ; // Looks like we found it! But let's just // perform a few more checks to be sure: if ( COL_SIG_REV1 != locator . signature ) continue ; // Let's make sure the hierarchy struct // is where it's supposed to be auto const & hierarchy = * ( _RTTIClassHierarchyDescriptor * )( base + locator . pClassDescriptor ); // Hierarchy struct should always have // a signature set to 0 if ( 0u != hierarchy . signature ) continue ; // The hierarchy attributes are limited // in what they can be set to if ( hierarchy . attributes > ( CHD_MULTINH | CHD_VIRTINH | CHD_AMBIGUOUS ) ) continue ; // Ok we've done enough checking, we've found the RTTI return & locator ; } } class type_info_iterator { friend class type_info ; char const * base = nullptr ; int32_t const * pp = nullptr ; public : type_info const & operator * ( void ) const noexcept { auto const & baseclass = * ( _RTTIBaseClassDescriptor * )( base + * pp ); return * ( type_info * )( base + baseclass . pTypeDescriptor ); } type_info const * operator -> ( void ) const noexcept { return &** this ; } type_info_iterator & operator ++ ( void ) noexcept { ++ pp ; return * this ; } ptrdiff_t operator - ( type_info_iterator const & rhs ) noexcept { assert ( this -> base == rhs . base ); return this -> pp - rhs . pp ; } bool operator != ( type_info_iterator const & rhs ) const noexcept { return ! (( this -> base == rhs . base ) && ( this -> pp == rhs . pp )); } }; pair < type_info_iterator , type_info_iterator > type_info :: bases ( type_info const & ti ) const noexcept { _RTTICompleteObjectLocator const & locator = * type_info_to_locator ( & ti ); char * const base = ( char * ) & locator - locator . pSelf ; _RTTIClassHierarchyDescriptor const & hierarchy = * ( _RTTIClassHierarchyDescriptor * )( base + locator . pClassDescriptor ); assert ( 0u != hierarchy . signature ); if ( 0 == hierarchy . numBaseClasses ) return {}; int32_t const * nbaseclass = ( int32_t * )( base + hierarchy . pBaseClassArray ); pair < type_info_iterator , type_info_iterator > retval ; retval . first . base = retval . second . base = base ; retval . first . pp = nbaseclass ; retval . second . pp = nbaseclass + hierarchy . numBaseClasses ; return retval ; }
3. Design considerations
The aim is to add as much information as possible to
without causing an ABI break on any extant compilers, specifically
paying attention to the Itanium ABI (used by GNU, LLVM, Intel) and
the Microsoft ABI (used in Visual C++).
4. Proposed wording
The proposed wording is relative to [N4950].
In subclause __________
1 -- I'll write this later
5. Impact on the standard
This proposal is a library extension. The addition has no effect on any other part of the standard.
6. Impact on existing code
No existing code becomes ill-formed. The behaviour of all existing code is unaffected.