wake-up-neo.com

Konvertieren von Typname T in String in C++

Beim Spielen mit Vorlagen in C++ ist ein Problem beim Konvertieren von Typname T in String aufgetreten. Zum Beispiel:

template <typename T>
class Matrix {
   public:
        Matrix() {
           //my_type = string type of T. i.e. if T is char. I want my_type to be "char".
        }
   string my_type;
}

Wie konvertiere ich T in einen String, der sagt, was T ist?.

Hinweis: Ich spiele nur herum, also mach dir keine Sorgen, wann man so etwas braucht.

53
Srikanth

Dafür gibt es keinen eingebauten Mechanismus. typeid(T)::name() kann einige Informationen geben, aber der Standard verlangt nicht, dass diese Zeichenfolge für Menschen lesbar ist. einfach für jeden Typ zu unterscheiden. Microsoft Visual C++ verwendet für Menschen lesbare Zeichenfolgen. GCC tut nicht.

Sie können jedoch Ihr eigenes System erstellen. Zum Beispiel auf der Grundlage von Merkmalen. Etwas wie das:

// default implementation
template <typename T>
struct TypeName
{
    static const char* Get()
    {
        return typeid(T).name();
    }
};

// a specialization for each type of those you want to support
// and don't like the string returned by typeid
template <>
struct TypeName<int>
{
    static const char* Get()
    {
        return "int";
    }
};

// usage:
const char* name = TypeName<MyType>::Get();
56
atzz

Für GCC musst du einen Trick benutzen. Mit cxxabi.h.__ habe ich dazu einen kleinen Wrapper geschrieben.

#include <string>
#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <cxxabi.h>

#define DEBUG_TYPE(x) do { typedef void(*T)x; debug_type<T>(T(), #x); } while(0)

template<typename T>
struct debug_type
{
    template<typename U>
    debug_type(void(*)(U), const std::string& p_str)
    {
        std::string str(p_str.begin() + 1, p_str.end() - 1);
        std::cout << str << " => ";
        char * name = 0;
        int status;
        name = abi::__cxa_demangle(typeid(U).name(), 0, 0, &status);
        if (name != 0) { std::cout << name << std::endl; }
        else { std::cout << typeid(U).name() << std::endl; }
        free(name);
    }
};

Doppelte Elternschaft ist notwendig. Funktioniert mit jedem Typ.

Jetzt können Sie es für boost :: mpl verwenden:

DEBUG_TYPE((if_c<true, true_, false_>::type));

wird druckt:

if_c<true, true_, false_>::type => bool_<true>

Das geht nicht, zumindest nicht direkt. Die einzige Möglichkeit, ein Token oder eine Serie von Token in ein String-Literal zu konvertieren, besteht darin, den Stringisierungsoperator (#) des Präprozessors innerhalb eines Makros zu verwenden. 

Wenn Sie ein Zeichenfolgenliteral abrufen möchten, das den Typ darstellt, müssen Sie selbst etwas schreiben, z. B. durch Verwendung eines Makros, um die Vorlage zu instanziieren, und übergeben Sie den Namenstyp mit Zeichenfolge.

Ein Problem bei jedem allgemeinen Ansatz ist: Welche Zeichenfolge sollte für die folgenden Zwecke angegeben werden:

Matrix<char> x;
typedef char MyChar;
Matrix<MyChar> y;

Sowohl x als auch y sind vom selben Typ, aber einer verwendet char direkt und der andere verwendet das typedef MyChar.

6
James McNellis

problemumgehung ...

#define Tprint(x) print<x>(#x)

template<typename T>
void print (string ltype){
cout<<ltype<<" = "<<sizeof(T)<<endl;
}
2
user3071398

Es ist nicht möglich, den Namen des Typs in string zu erhalten, wenn es sich um einen Basistyp handelt. Für benutzerdefinierte Typen können Sie typeid(my_type).name() verwenden. Außerdem benötigen Sie #include <typeinfo>:) weitere Informationen ...

2

Sie können eine C++ - Reflektionsbibliothek verwenden. So:

using namespace ponder;

Class::declare<Matrix>();

std::string const& name = classByType<Matrix>().name();

Dadurch haben Sie auch andere Optionen, sobald Sie über die Metaklassendaten verfügen, z. B. nach den Klassenmitgliedern.

0
Nick