typeid pointer recursion

Hello all,

ive created a function named typeof that either takes any object and shows the typeid().name() result on operator<< or takes a pointer and prints the type pointed to.
Example:
1
2
int* (0x61fe00)
Process finished with exit code 0

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;

std::map<size_t, const char *> _reps{
        {typeid(char).hash_code(), "char"},
        {typeid(short).hash_code(), "short"},
        {typeid(unsigned short).hash_code(), "unsigned short"},
        {typeid(int).hash_code(), "int"},
        {typeid(unsigned int).hash_code(), "unsigned"},
        {typeid(long unsigned int).hash_code(), "long unsigned"},
        {typeid(long long int).hash_code(), "long long"},
        {typeid(long int).hash_code(), "long"},
        {typeid(double).hash_code(), "double"},
        {typeid(long double).hash_code(), "long double"},
        {typeid(float).hash_code(), "float"},
        {typeid(unsigned char).hash_code(), "unsigned char"}
};


template<typename _T>
class _TH
{
    _T obj;
    template<typename T>
    friend ostream& operator<<(ostream& os, const _TH<T>& elem)
    {
        const size_t hc = typeid(T).hash_code();
        if (_reps.find(hc) == _reps.end())
            return os << typeid(elem.obj).name(); // ouput example: int
        return os << _reps[hc]; // output example "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"
    }

public:

    _TH(_T t): obj{t} {}

};

template<typename _T>
class _THP
{
    _T obj;
    template<typename T>
    friend ostream& operator<<(ostream& os, const _THP<T *>& elem)
    {
        const size_t hc = typeid(*elem.obj).hash_code();
        if (_reps.find(hc) == _reps.end())
            return os << typeid(*elem.obj).name() << "*" << " (" << &elem.obj << ")"; // output example "int* (0x61fe00)"
        return os << _reps[hc] << "*" << " (" << &elem.obj << ")"; // output example: "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE* (0x61fe00)"
    }

public:
    _THP(_T t): obj{t} {}
};


// copy or move
template<typename T>
_TH<T> typeof(T &&obj)
{
    return _TH<T>{obj};
}

 // pointers
template<typename T>
_THP<T *> typeof(T *obj)
{
    return _THP<T *>{obj};
}



int main()
{
    int *dptr = new int;
    *dptr = 12;
    string h{"Hell"};

    cout << typeof(dptr);

    delete dptr;
}



Now, the thing is, if i would pass typeof(dptr) with pointer depth of 2, than i cannot figure out where to stop dereferencing and which depth the pointer given is, to be capable of printing somethin like "int ** (0x61fe00)".
If i would want that, id need to add a third overload for typeof and declare another class. Is there any way to use a recursion?

Thank you

Luke
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <typeinfo>
#include <type_traits>
#include <string>
#include <cstring>

#ifdef __GNUG__ // GNU or compatible

  #include <cxxabi.h>
  #include <cstdlib>
  #include <memory>

  std::string demangle( const char* raw_name )
  {
      int result ;
      std::unique_ptr< char, decltype(&std::free) > ptr(
         __cxxabiv1::__cxa_demangle( raw_name, nullptr, nullptr, std::addressof(result) ),
         &std::free ) ;
      return result == 0 ? ptr.get() : raw_name ;
  }

  template < typename T > std::string qualifiers()
  {
      std::string qualifier_token ;
      if( std::is_const<T>::value ) qualifier_token += "const " ;
      if( std::is_volatile<T>::value ) qualifier_token += "volatile " ;
      return qualifier_token ;
  }

#else // hopefully microsoft or compatible

  #include <regex>
  std::string demangle( const char* raw_name )
  {
      std::string str = raw_name ;
      return std::regex_replace( str, std::regex( "\\[0\\]" ), "[]" ) ;
  }

  template < typename T > std::string qualifiers() { return {} ; }

#endif // _GNUG_

template < typename T > std::string type_desc( T&& )
{ return qualifiers<T>() + demangle( typeid(T).name() ) ; }

template < typename T > std::string type_desc()
{ return qualifiers<T>() + demangle( typeid(T).name() ) ; }

namespace one { struct two{ using type = int ; }; }

int main()
{
    using cvot = const volatile one::two ;
    using arr_type = cvot[5][3] ;
    cvot**** ptr = nullptr ;
    arr_type**** ptr_array = nullptr ;
    std::cout << type_desc(ptr) << '\n'
              << type_desc(ptr_array) << '\n'
              << type_desc( std::addressof(std::strcpy) ) << '\n' ;
}

http://coliru.stacked-crooked.com/a/e5dd2166607d6e13
wow, you are incredible, thank you very much!!
Last edited on
I just dont get what of a magic this regex does:
"return std::regex_replace( str, std::regex( "\\[0\\]" ), "[]" ) ;"
could you tell me please?
https://regex101.com/
(I have no idea what it does either, but you can play with it there & look up what the tokens do).
Last edited on
the regex_replace replaces [0] (if any) with []

For an array of unknown bound, microsoft gives [0]:
1
2
3
4
5
int main()
{
    std::cout << typeid( int[] ).name() << '\n' // int[0]
              << demangle( typeid( int[] ).name() ) << '\n' ; // int[]
}
Ok, sounds logic, but why does the function demangle then returns "one::two" from "PPPPA5_A3_VKN3one3twoE" gobble?
For GNU and compatible implementations, we are using __cxxabiv1::__cxa_demangle to demangle the name.
https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html

std::type_info::name
Some implementations (such as MSVC, IBM, Oracle) produce a human-readable type name. Others, most notably gcc and clang, return the mangled name, which is specified by the Itanium C++ ABI. The mangled name can be converted to human-readable form using implementation-specific API such as abi::__cxa_demangle directly or through boost::core::demangle. It can also be piped through the commandline utility c++filt -t.
https://en.cppreference.com/w/cpp/types/type_info/name#Notes
Okay, cool. Thanks a lot :)
Learned something new again.
have a nice day
Topic archived. No new replies allowed.