Type name damping problem

I created a template class that converts the type to a string describing it, for example typeinfo<int(*)()>::name() returns the string "int(*)()" (before the space). Initially, I had many special cases to get around the fact that typeid(...).name() rejects the top-level cv qualifiers and qualifiers, but then I remembered that passing the type as a template parameter would save them. So, using the ABI header, I got something like this:

 #include <iostream> #include <typeinfo> #include <string> #include <cxxabi.h> using namespace std; string demangle(const char* mangledName) { int status; char* result = abi::__cxa_demangle(mangledName, nullptr, nullptr, &status); switch(status) { case -1: cerr << "Out of memory!" << endl; exit(1); case -2: return mangledName; case -3: // Should never happen, but just in case? return mangledName; } string name = result; free(result); return name; } template<typename T> struct preserve_qualifiers {}; template<typename T> class typeinfo { using wrap = preserve_qualifiers<T>; public: static const string name() { string name = demangle(typeid(wrap).name()); int i = name.find_first_of('<'); if(i == string::npos) return name; int j = name.length() - i - 2; return name.substr(i + 1, j); } }; #define TypeOut(...) cout \ << "Type " #__VA_ARGS__ ": " << endl \ << " Mangled: " << typeid(__VA_ARGS__).name() << endl \ << " Demangled: " << demangle(typeid(__VA_ARGS__).name()) << endl \ << " typeinfo<>: " << typeinfo<__VA_ARGS__>::name() << endl class A {}; template<typename T> class F {}; template<int T> class G {}; template<template<typename> class T> class H {}; template<template<int> class T> class I {}; template<typename... T> class J {}; template<int... T> class K {}; template<template<typename> class... T> class L {}; template<template<int> class... T> class M {}; template<template<typename> class... T> class N {}; template<template<template<typename> class...> class... T> class O {}; struct bits {int i : 4, j : 2;}; template<typename T, int n> struct bits2 {T val : n;}; int main(int argc, char* argv[]) { TypeOut(void(*volatile)(void(*const)())); TypeOut(int (A::*)()); TypeOut(int (A::*)()const); TypeOut(int (A::*const)()); #ifdef __clang__ TypeOut(int (A::*)()&); TypeOut(int (A::*)()&&); #endif TypeOut(F<int>); TypeOut(G<3>); TypeOut(H<F>); TypeOut(I<G>); TypeOut(J<int>); TypeOut(K<3>); TypeOut(L<F>); TypeOut(M<G>); TypeOut(N<F,F,F>); TypeOut(O<N,N>); } 

This compiles and works (almost) perfectly in GCC (4.8). However, GCC does not support ref-qualifiers for member functions, so I tried it in Clang (3.2) to make sure this works. This is not true. It compiles fine and runs without problems, but most template names are not demarcated, as well as the ref-qual member function.

Here is the GCC output from ideone (the code has been slightly modified since the ideal version of GCC does not support nullptr or alias declarations). Note the missing constant determinant in the function parameter. This is the only thing that did not work, as I had hoped in the GCC. This is the same in Klang, which, I believe, is not particularly surprising. (What is surprising is that it is absent altogether, and not that GCC and Clang agree on it.)

Unfortunately, when compiling and running with Clang, variational template classes could not be decoupled. For example, J was distorted to 1JIJiEE instead of 1JIIiEE , which GCC chose.

Selected exit from clang (showing only those that do not work)

 Type int (A::*)()&: Mangled: M1AFivRE Demangled: M1AFivRE typeinfo<>: 19preserve_qualifiersIM1AFivREE Type int (A::*)()&&: Mangled: M1AFivOE Demangled: M1AFivOE typeinfo<>: 19preserve_qualifiersIM1AFivOEE Type J<int>: Mangled: 1JIJiEE Demangled: 1JIJiEE typeinfo<>: 19preserve_qualifiersI1JIJiEEE Type K<3>: Mangled: 1KIJLi3EEE Demangled: 1KIJLi3EEE typeinfo<>: 19preserve_qualifiersI1KIJLi3EEEE Type L<F>: Mangled: 1LIJ1FEE Demangled: 1LIJ1FEE typeinfo<>: 19preserve_qualifiersI1LIJ1FEEE Type M<G>: Mangled: 1MIJ1GEE Demangled: 1MIJ1GEE typeinfo<>: 19preserve_qualifiersI1MIJ1GEEE Type N<F,F,F>: Mangled: 1NIJ1FS0_S0_EE Demangled: 1NIJ1FS0_S0_EE typeinfo<>: 19preserve_qualifiersI1NIJ1FS1_S1_EEE Type O<N,N>: Mangled: 1OIJ1NS0_EE Demangled: 1OIJ1NS0_EE typeinfo<>: 19preserve_qualifiersI1OIJ1NS1_EEE 

Does anyone know how to solve this? Is this a bug in clang? (Or maybe a bug in GCC?) My first suspicion was version incompatibility between the C ++ ABI associated with my code and the C ++ ABI that uses clang. The fact that the problem only occurs with the new C ++ 11 features (ref-qualifiers for function members and variational patterns) seems to support this suspicion ... although r-value references (for example) have no problem.

In case that matters, I'm on Mac OSX Lion, and GCC 4.8 and clang 3.2 were installed from MacPorts. I use the following commands to compile:

 clang++-mp-3.2 -isystem/usr/local/include/c++/v1 -stdlib=libc++ -std=gnu++11 typeinfo-min.cpp -o typeinfofun-clang G++-mp-4.8 -std=gnu++11 typeinfo-min.cpp -o typeinfofun-gcc 

The isystem flag is required to allow clang to find libC ++ headers (which was necessary when I used <type_traits> for a more complex version of this). Without him, he cannot even find <iostream> .

(As an additional note, this problem also affects the more complex version, since the class names were probably not surprising - not among the specializations for complex types, and therefore simply used the ABI demangle call.)

(As well as to the side, I am curious how portable this is. I know that this is not necessary in MSVC, as it returns an intact name from typeid(...).name() , but other than that ...)

+8
c ++ c ++ 11
source share
1 answer

I checked gcc4.8 mingw3.0 your example:

gcc version 4.8.1 20130324 (pre-transmission) (rubenvb-4.8-stdthread)

 c++.exe -ggdb -Os -frtti -fexceptions -fpic -std=gnu++11 

And I got this result

 Type void(*volatile)(void(*const)()): Mangled: PFvPFvvEE Demangled: void (*)(void (*)()) typeinfo<>: void (* volatile)(void (*)()) Type int (A::*)(): Mangled: M1AFivE Demangled: int (A::*)() typeinfo<>: int (A::*)() Type int (A::*)()const: Mangled: M1AKFivE Demangled: int (A::*)() const typeinfo<>: int (A::*)() const Type int (A::*const)(): Mangled: M1AFivE Demangled: int (A::*)() typeinfo<>: int (A::* const)() Type F<int>: Mangled: 1FIiE Demangled: F<int> typeinfo<>: F<int> Type G<3>: Mangled: 1GILi3EE Demangled: G<3> typeinfo<>: G<3> Type H<F>: Mangled: 1HI1FE Demangled: H<F> typeinfo<>: H<F> Type I<G>: Mangled: 1II1GE Demangled: I<G> typeinfo<>: I<G> Type J<int>: Mangled: 1JIIiEE Demangled: J<int> typeinfo<>: J<int> Type K<3>: Mangled: 1KIILi3EEE Demangled: K<3> typeinfo<>: K<3> Type L<F>: Mangled: 1LII1FEE Demangled: L<F> typeinfo<>: L<F> Type M<G>: Mangled: 1MII1GEE Demangled: M<G> typeinfo<>: M<G> Type N<F,F,F>: Mangled: 1NII1FS0_S0_EE Demangled: N<F, F, F> typeinfo<>: N<F, F, F> Type O<N,N>: Mangled: 1OII1NS0_EE Demangled: O<N, N> typeinfo<>: O<N, N> 
+1
source share

All Articles