Odd string returned from typeid

I'm developing a template function that takes in containers as a parameter. The function will use typeid to check if a container was passed in or not. Since I've never used typeid before, I played around with it but got strange results.

This is my main function:
1
2
3
4
5
6
7
8
9
10
11
int main(){
      //Custom class defined in separate file
   Vectors::VectorData Testrun = {1,2,3};
   int regular;
   vector<double> newvector;
   cout << typeid(int).name() << endl;
   cout << "regular is of type: " << typeid(regular).name() << endl;
   cout << "newvector variable is of type: " << typeid(newvector).name() << endl;
   cout << "Class type is: " << typeid(Testrun).name() << std::endl;
   
}

Here is what I get:

i
regular is of type: i
newvector variable is of type: St6vectorIdSaIdEE
Class type is: N7Vectors10VectorDataE


Should this be something to be worried about? Are there any repercussions to be aware of?
http://www.cplusplus.com/reference/typeinfo/type_info/name/
Returns a null-terminated character sequence that may identify the type.
The particular representation pointed by the returned value is implementation-defined, and may or may not be different for different types.

http://en.cppreference.com/w/cpp/types/type_info/name
Returns an implementation defined null-terminated character string containing the name of the type. No guarantees are given, in particular, the returned string can be identical for several types and change between invocations of the same program.
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
#include <iostream>
#include <string>
#include <typeinfo>

#ifdef __GNUG__ // GCC

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

static std::string readable_name( const char* mangled_name )
{
    int status ;
    char* temp = __cxxabiv1::__cxa_demangle( mangled_name, nullptr, nullptr, &status ) ;
    if(temp)
    {
        std::string result(temp) ;
        std::free(temp) ;
        return result ;
    }
    else return mangled_name ;
}

#else // not GCC

inline std::string readable_name( const char* mangled_name ) { return mangled_name ; }

#endif // __GNUG__

template < typename T > std::string type_to_string()
{ return readable_name( typeid(T).name() ) ; }

template < typename T > std::string type_to_string( const T& obj )
{ return readable_name( typeid(obj).name() ) ; }

#include <vector>

int main()
{
    std::vector<std::string> seq ;

    std::cout << type_to_string( 1234 ) << '\n'
               << type_to_string( std::realloc ) << '\n'
               << type_to_string( std::cout ) << '\n'
               << type_to_string( std::cin.rdbuf() ) << '\n'
               << type_to_string( *std::cin.rdbuf() ) << '\n'
               << type_to_string( std::string::npos ) << '\n'
               << type_to_string<std::string::iterator>() << '\n'
               << type_to_string( seq ) << '\n'
               << type_to_string( seq.size() ) << '\n'
               << type_to_string< decltype( std::srand(9) ) >() << '\n' ;
}


http://ideone.com/GZEGN6
Last edited on
To explain what JLBorges did:
He have used GCC specific function __cxa_demangle() to convert type_info.name() output to readable format.
http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html

Also he have used conditional compilation to make sure that code will compile on all compilers (however on compilers different from GCC it will not change anything: you still get type name in whatever format that compiler uses)

The function will use typeid to check if a container was passed in or not
I want to point that your code will not work with user defined containers (If I create class MyCoolStack which satisfies all requirements to containers it will probably be not accepted by your function). In C++14 there will be Constraints which will work with user defined types and can do exactly what you want. (I am not saying that you should drop what you doing now and wait for C++14, just telling you some information)
> The function will use typeid to check if a container was passed in or not

Simpler to use SFINAE for this.

For example, using spirit:
http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/advanced/customize/is_container.html
(Specialize boost::spirit::traits::is_container<> for user defined types that meet the requirements of a standard library compatible container.)

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
#include <typeinfo>
#include <string>

#ifdef __GNUG__ // GCC

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

static std::string readable_name( const char* mangled_name )
{
    int status ;
    char* temp = __cxxabiv1::__cxa_demangle( mangled_name, nullptr, nullptr, &status ) ;
    if(temp)
    {
        std::string result(temp) ;
        std::free(temp) ;
        return result ;
    }
    else return mangled_name ;
}

#else // not GCC

inline std::string readable_name( const char* mangled_name ) { return mangled_name ; }

#endif // __GNUG__

template < typename T > std::string type_to_string()
{ return readable_name( typeid(T).name() ) ; }

template < typename T > std::string type_to_string( const T& obj )
{ return readable_name( typeid(obj).name() ) ; }

////////////////////////   code added in this post ////////////////////////////
#include <boost/spirit/home/support/container.hpp>
#include <type_traits>
#include <iterator>
#include <iostream>

template < typename T >
typename std::enable_if< boost::spirit::traits::is_container<T>::value, bool >::type
is_it_a_container( T&& v )
{
    std::cout << "yes, this is a container holding values of type "
               << type_to_string< decltype( *std::begin(v) ) >() << '\n' ;
    return true ;
}

template < typename T >
typename std::enable_if< !boost::spirit::traits::is_container<T>::value, bool >::type
is_it_a_container( T&& ) { std::cout << "no, this is not a container\n" ; return false ; }

///////////////////////////////////////////////////////////////////////////////////////////////

#include <vector>
#include <tuple>

int main()
{
    int a ;
    std::cout << std::boolalpha << is_it_a_container(a) << "\n\n" ;
    // no, this is not a container
    // false

    std::vector< std::tuple<int,double,char> > b ;
    std::cout << is_it_a_container(b) << '\n' ;
    // yes, this is a container holding values of type std::tuple<int, double, char>
    // true
}

@JLBorges
Ah okay, thanks. I'm pretty unfamiliar with boost and even more so with cxxabi.h, so this will take some time to understand.

@MiiNiPaa
Thanks for the information. I'll need to practice formulating some designs anyway like playing with JLBorges' sample code, so I'll better understand all of it.
> I'm pretty unfamiliar with boost and even more so with cxxabi.h, so this will take some time to understand.

An understanding of SFINAE is fundamental to understanding C++ templates, and the concept is simple:
if an invalid argument or return type is formed during the instantiation of a function template, the instantiation is removed from the overload resolution set instead of causing a compilation error.


A simple example, using nothing other than standard C++:
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
#include <iostream>

template < typename T > void foo( T, typename T::const_iterator* = nullptr )
{ std::cout << "(1) this type defines a nested type 'const_iterator'\n" ; }

template < typename T > void foo( T, typename T::first_type* = nullptr )
{ std::cout << "(2) this type defines a nested type 'first_type'\n" ; }

template < typename T > void foo( T, typename T::result_type* = nullptr )
{ std::cout << "(3) this type defines a nested type 'result_type'\n" ; }

#include <vector>
#include <utility>
#include <functional>

int main()
{
    std::vector<int> a ;
    foo(a) ; // (1) this type defines a nested type 'const_iterator'
    // substitution failure for (2) and (3)

    std::pair<int,int> b ;
    foo(b) ; // (2) this type defines a nested type 'first_type'
    // substitution failure for (1) and (3)

    std::function< bool(int,int) > c ;
    foo(c) ; // (3) this type defines a nested type 'result_type'
    // substitution failure for (1) and (2)
}


http://ideone.com/xRwbNm

In the snippet posted earlier, boost spirit was used for convenience. Checking if a type meets the requirement of a container involves many checks (in addition to 'does the type define a 'const_iterator'?); and the library had already implemented those checks.
Topic archived. No new replies allowed.