Den Typ einer Variablen als String ausgeben.



  • Da mit C++11 ja auto eingeführt wurde, hätte ich gerne eine funktion, die mir zur Laufzeit die Typen, die auto ermittelt hat anzeigt. (klar nur zu debug-zwecken)

    dazu gibt es ja das bekannte typeid, allerdings liefert mein gcc dabei ausgaben, die nichtssagend sind.

    Boost bietet desswegen neuerdings die Boost.TypeIndex Lib an, allerdings entwickle ich unter Debian(jessie) und dort ist 1.55 installiert. Die TypeIndex Lib ist allerdings erst ab 1.56 mit dabei. In Absehbarer Zeit (mind. 2 Jahre wird sich wohl das nicht ändern, da jessie noch nicht mal fertig ist.

    Meine Frage nun, kennt ihr eine lib, die das macht, also der ich eine Variable übergebe und die mir dazu die Typen ausgibt?
    Gerne nehme ich auch Compiler-hacks, also funktionen, die es beispielsweise nur im GCC gibt, da ich diese funktion nur zu debug-zwecken benötige.

    Dadurch dass ich auch selbst keine alternative gekannt hab, habe ich mal kurzerhand eine funktion selbst geschrieben, allerdings hat die den nachteil, dass ich erst jeden typ damit bekannt machen muss. (in der streamoperatorüberladung ist das die map, in der die typen eingetragen werden müssen.

    zum beispiel im folgenden MWE müsste der int-vektor erst hinzugefügt werden.

    #include <iostream>
    #include <typeinfo>
    #include <typeindex>
    #include <sstream>
    #include <map>
    #include <vector>
    
    std::ostream& operator<< (std::ostream& out, const std::type_index& idx) noexcept
    {
        static const std::map<std::type_index, std::string> types{
            {std::type_index(typeid(int)), "int"},
            {std::type_index(typeid(double)), "double"},
            {std::type_index(typeid(std::string)), "std::string"},
            {std::type_index(typeid(const char*)), "const char*"}
        };
    
        try{
            out << types.at(idx);
        } catch (std::out_of_range& e){
            out << "unknown";
        } catch (...) {
            throw;
        }
        return out;
    }
    
    template<typename T> struct is_const_reference : std::false_type {};
    template<typename T> struct is_const_reference<const T&> : std::true_type {};
    
    template<typename T>
    std::string get_type(T var) {
        std::stringstream ss;
        if(is_const_reference<decltype(var)>::value 
                || std::is_const<decltype(var)>::value) {
            ss << "const ";
        }
        ss << std::type_index(typeid(var));
        if(std::is_reference<decltype(var)>::value) {
            if(std::is_lvalue_reference<decltype(var)>::value) {
                ss << "&";
            } else if(std::is_rvalue_reference<decltype(var)>::value) {
                ss << "&&";
            }
        }
        return ss.str();
    }
    
    int main() {
        int i=2;
        const int ci=1;
        const int& cri=i;
        int& ri = i;
    
        //is in the list, work like expected...
        std::cout << get_type<decltype(i)>(i) << std::endl;
        std::cout << get_type<decltype(ci)>(ci) << std::endl;
        std::cout << get_type<decltype(cri)>(cri) << std::endl;
        std::cout << get_type<decltype(ri)>(ri) << std::endl;
        std::cout << get_type<decltype(std::move(10))>(std::move(10)) 
                << std::endl << std::endl;
    
        //is not in the list, doesn't work...
        std::vector<int> vi;
        std::cout << get_type<decltype(vi)>(vi) << std::endl;
    }
    

    Die Ausgabe dazu:

    int
    const int
    const int&
    int&
    int&&
    
    unknown
    


  • Das Ergebnis von GCCs typeid().name ist der mangled name. In der cxxabi.h gibt es eine Funktion zum demanglen.
    Alternativ gibt dir __PRETTY_FUNCTION__ auch den Typen, mit dem ein Template instantiiert wurde.





  • Danke Cxxabi das hat mir sehr geholfen! *gg*


Log in to reply