629 Stimmen

Ist es möglich, den Typ einer Variablen in Standard-C++ zu drucken?

Zum Beispiel:

int a = 12;
cout << typeof(a) << endl;

Erwartetes Ergebnis:

int

3 Stimmen

Hier ist eine Zusammenfassung von Howards Langformlösung, die jedoch mit einem ketzerischen einzeiligen Makro umgesetzt wurde: #define DEMANGLE_TYPEID_NAME(x) abi::__cxa_demangle(typeid((x)).name(), NULL, NULL, NULL) . Wenn Sie plattformübergreifende Unterstützung benötigen: Verwenden Sie . #ifdef , #else , #endif um ein Makro für andere Plattformen wie MSVC bereitzustellen.

0 Stimmen

Mit expliziteren, für Menschen lesbaren Anforderungen: stackoverflow.com/questions/12877521/

3 Stimmen

Wenn Sie dies nur zum Debuggen verwenden, sollten Sie Folgendes in Betracht ziehen template<typename T> void print_T() { std::cout << __PRETTY_FUNCTION__ << '\n'; } . Dann verwenden Sie z.B. print_T<const int * const **>(); wird gedruckt void print_T() [T = const int *const **] zur Laufzeit und bewahrt alle Qualifier (funktioniert in GCC und Clang).

13voto

Greg Hewgill Punkte 882617

Hierfür könnte man eine Traits-Klasse verwenden. Etwas wie:

#include <iostream>
using namespace std;

template <typename T> class type_name {
public:
    static const char *name;
};

#define DECLARE_TYPE_NAME(x) template<> const char *type_name<x>::name = #x;
#define GET_TYPE_NAME(x) (type_name<typeof(x)>::name)

DECLARE_TYPE_NAME(int);

int main()
{
    int a = 12;
    cout << GET_TYPE_NAME(a) << endl;
}

Le site DECLARE_TYPE_NAME define existiert, um Ihnen das Leben zu erleichtern, indem Sie diese Traits-Klasse für alle Typen deklarieren, die Sie voraussichtlich benötigen werden.

Dies könnte nützlicher sein als die Lösungen, die typeid weil Sie die Kontrolle über die Ausgabe haben. Zum Beispiel, mit typeid para long long auf meinem Compiler ergibt "x".

13voto

abodeofcode Punkte 111

In C++11 haben wir decltype. In Standard-C++ gibt es keine Möglichkeit, den genauen Typ einer mit decltype deklarierten Variablen anzuzeigen. Wir können boost typeindex verwenden, d.h. type_id_with_cvr (cvr steht für const, volatile, reference), um den Typ wie unten zu drucken.

#include <iostream>
#include <boost/type_index.hpp>

using namespace std;
using boost::typeindex::type_id_with_cvr;

int main() {
  int i = 0;
  const int ci = 0;
  cout << "decltype(i) is " << type_id_with_cvr<decltype(i)>().pretty_name() << '\n';
  cout << "decltype((i)) is " << type_id_with_cvr<decltype((i))>().pretty_name() << '\n';
  cout << "decltype(ci) is " << type_id_with_cvr<decltype(ci)>().pretty_name() << '\n';
  cout << "decltype((ci)) is " << type_id_with_cvr<decltype((ci))>().pretty_name() << '\n';
  cout << "decltype(std::move(i)) is " << type_id_with_cvr<decltype(std::move(i))>().pretty_name() << '\n';
  cout << "decltype(std::static_cast<int&&>(i)) is " << type_id_with_cvr<decltype(static_cast<int&&>(i))>().pretty_name() << '\n';
  return 0;
}

1 Stimmen

Wäre es einfacher, eine Hilfsfunktion zu verwenden: template<typename T> void print_type(T){cout << "type T is: "<< type_id_with_cvr<T>().pretty_name()<< '\n';}

11voto

Alan Punkte 1279

Sie können auch c++filt mit der Option -t (Typ) verwenden, um den Typnamen zu entschlüsseln:

#include <iostream>
#include <typeinfo>
#include <string>

using namespace std;

int main() {
  auto x = 1;
  string my_type = typeid(x).name();
  system(("echo " + my_type + " | c++filt -t").c_str());
  return 0;
}

Nur unter Linux getestet.

1 Stimmen

Verdammt hässlich, aber für das, was ich brauche, völlig ausreichend. Und viel kleiner als die anderen Lösungen. Funktioniert auf Mac btw.

8voto

James Hopkin Punkte 13389

Die anderen Antworten, die RTTI (typeid) beinhalten, sind wahrscheinlich das, was Sie wollen, solange:

  • Sie können sich den Speicher-Overhead leisten (der bei einigen Compilern beträchtlich sein kann)
  • die Klassennamen, die Ihr Compiler zurückgibt, sind nützlich

Die Alternative (ähnlich wie die Antwort von Greg Hewgill) besteht darin, eine Kompilierzeittabelle mit Merkmalen zu erstellen.

template <typename T> struct type_as_string;

// declare your Wibble type (probably with definition of Wibble)
template <>
struct type_as_string<Wibble>
{
    static const char* const value = "Wibble";
};

Beachten Sie, dass Sie, wenn Sie die Deklarationen in ein Makro verpacken, aufgrund des Kommas Probleme haben werden, Namen für Schablonentypen zu deklarieren, die mehr als einen Parameter haben (z.B. std::map).

Um auf den Namen des Typs einer Variablen zuzugreifen, brauchen Sie nur

template <typename T>
const char* get_type_as_string(const T&)
{
    return type_as_string<T>::value;
}

1 Stimmen

Das mit dem Komma ist ein guter Punkt. Ich wusste, dass es einen Grund gibt, warum Makros keine gute Idee sind, aber ich habe damals nicht daran gedacht!

2 Stimmen

Static const char* value = "Wibble"; das geht nicht, Kumpel :)

7voto

Milo Lu Punkte 2869

Wie von Scott Meyers in Effective Modern C++ erläutert,

Anrufe an std::type_info::name sind keine Garantie dafür, dass sie etwas Vernünftiges ergeben.

Die beste Lösung besteht darin, den Compiler während der Typerkennung eine Fehlermeldung generieren zu lassen, zum Beispiel,

template<typename T>
class TD;

int main(){
    const int theAnswer = 32;
    auto x = theAnswer;
    auto y = &theAnswer;
    TD<decltype(x)> xType;
    TD<decltype(y)> yType;
    return 0;
}

Das Ergebnis sieht dann je nach Compiler etwa so aus,

test4.cpp:10:21: error: aggregate ‘TD<int> xType’ has incomplete type and cannot be defined TD<decltype(x)> xType;

test4.cpp:11:21: error: aggregate ‘TD<const int *> yType’ has incomplete type and cannot be defined TD<decltype(y)> yType;

Daher erfahren wir, dass x ist der Typ int , y ist der Typ const int*

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X