Drucken Sie den Namen des Vorlagentyps zur Kompilierzeit

Lesezeit: 9 Minuten

Benutzer-Avatar
Gabriel Süd

Gibt es beim Erstellen einer Vorlagenfunktion in C++ eine einfache Möglichkeit, den Typnamen der Vorlage als Zeichenfolge darzustellen? Ich habe einen einfachen Testfall, um zu zeigen, was ich versuche (beachten Sie, dass der gezeigte Code nicht kompiliert wird):

#include <stdio.h>
template <typename type>
type print(type *addr) 
{
  printf("type is: %s",type);
}

int main()
{
  int a;
  print(&a);
}

// Would like to print something like:
// type is: int

Ich denke, dass der Typname zur Kompilierzeit verfügbar sein sollte, wenn die Funktion instanziiert wird, aber ich bin mit Vorlagen nicht so vertraut und habe keine Möglichkeit gesehen, den Typnamen als Zeichenfolge zu erhalten.

Der Grund, warum ich dies tun möchte, ist das Debuggen von printf-Typen. Ich habe mehrere Threads, die ausgeführt werden, und das schrittweise Durchlaufen mit gdb ändert das Programmverhalten. Für einige Dinge möchte ich also Informationen darüber ausgeben, welche Funktionen ausgeführt wurden. Es ist nicht zu wichtig, wenn die Lösung zu komplex ist, würde ich das Hinzufügen dieser Informationen zu meiner Protokollierungsfunktion überspringen. Aber wenn es eine einfache Möglichkeit gäbe, dies zu tun, wäre dies eine nützliche Information.

  • Versuchen typeid (type).name() nach dem Einfügen von

    – Chris

    21. März 2012 um 21:44 Uhr

  • brauchen Sie es unbedingt zur Kompilierzeit? Andernfalls, typeid(type).name() könnte helfen.

    – Philipp

    21. März 2012 um 21:45 Uhr

  • Macht nichts, ich habe das Kompilierzeit-Ding nicht gesehen, aber wenn Sie es drucken, können Sie es sicher zur Laufzeit herausfinden.

    – Chris

    21. März 2012 um 21:46 Uhr

  • Ich hatte einmal eine Frage, um zu sehen, ob ein Vorlagenargument ungültig ist, damit es nichts zurückgibt. Wenn es hilft, ist es hier: stackoverflow.com/questions/9625526/…

    – Chris

    21. März 2012 um 21:54 Uhr

  • Ich glaube nicht, dass es eine Möglichkeit gibt, den Namen zur Kompilierzeit zu erhalten, da Sie damit nicht viel Nützliches anfangen können. typeid::name() ist die richtige Antwort dort.

    – Muhende Ente

    21. März 2012 um 22:05 Uhr

Benutzer-Avatar
matu

So erhalten Sie einen nützlichen Namen für die Kompilierzeit:

Angenommen, Sie haben einen unbekannten Typ namens “T”. Sie können den Compiler dazu bringen, seinen Typ auszugeben, indem Sie ihn fürchterlich verwenden. Zum Beispiel:

typedef typename T::something_made_up X;

Die Fehlermeldung wird wie folgt aussehen:

error: no type named 'something_made_up' in 'Wt::Dbo::ptr<trader::model::Candle>'

Das Bit nach ‘in’ zeigt den Typ. (Nur mit Clang getestet).

Andere Möglichkeiten, es auszulösen:

bool x = T::nothing;   // error: no member named 'nothing' in 'Wt::Dbo::ptr<trader::model::Candle>'
using X = typename T::nothing;  // error: no type named 'nothing' in 'Wt::Dbo::ptr<trader::model::Candle>'

Mit C++11 haben Sie möglicherweise bereits ein Objekt und verwenden „decltype“, um seinen Typ abzurufen, sodass Sie auch Folgendes ausführen können:

auto obj = creatSomeObject();
bool x = decltype(obj)::nothing; // (Where nothing is not a real member). 

  • Dies hilft wirklich beim Drucken von Typnamen zur Kompilierungszeit, wenn Sie Code haben, der nicht kompiliert wird!

    – Frau

    8. Juli 2015 um 22:40 Uhr


  • Die einzige Antwort, um die Frage tatsächlich zu beantworten!

    – Jeff Trull

    27. April 2016 um 22:49 Uhr

  • Funktioniert gut mit gcc zu.

    – Karikaturist

    14. Oktober 2016 um 19:20 Uhr

Benutzer-Avatar
David D

__PRETTY_FUNCTION__ sollte Ihr Problem lösen (zumindest zur Laufzeit)

Die Ausgabe an das folgende Programm ist:

asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf test<type>::test() [with type = int]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
asfdasdfasdf void tempFunction() [with type = bool]
!!!Hello World!!!

Wenn Sie den Typnamen wirklich, wirklich als Zeichenfolge benötigen, können Sie dies hacken (mithilfe von snprintf Anstatt von printf) und ziehen Sie die Teilzeichenfolge nach ‘=’ und vor ‘]’.

#include <iostream>
using namespace std;

template<typename type>
class test
{
public:
test()
{
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
}
};

template<typename type>
void tempFunction()
{
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
    printf("asfdasdfasdf %s\n", __PRETTY_FUNCTION__);
}

int main() {
    test<int> test;

    tempFunction<bool>();
    cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
    return 0;
}

  • Kompiliert nicht auf VS15.

    – Shinzu

    21. Januar 2016 um 19:15 Uhr

  • @kuhaku Es wird nur kompiliert, wenn Sie einen Compiler verwenden, der unterstützt SCHÖNE_FUNKTION. Überprüfen Sie diese Antwort, um Details zu sehen SCHÖNE_FUNKTION. Ebenfalls dieser Link zeigt Ihnen, welche Windows-Makros verwendet werden können, um dasselbe zu tun. Ich vermute Funk wird funktionieren, habe es aber nicht versucht oder versucht zu bestätigen. Ich verwende ausschließlich GCC, daher habe ich keine Umgebung zum Bestätigen.

    – David D

    27. Januar 2016 um 17:37 Uhr


  • Notiz: SCHÖNE_FUNKTION sollte __PRETTY_FUNCTION__ sein und Funk sollte __funktion__ sein

    – David D

    27. Januar 2016 um 17:45 Uhr


  • Nicht Kompilierzeit

    – Romário

    6. Juni 2020 um 4:19 Uhr

  • Dies ist mein Beispiel, um einen Typnamen mit PRETTY_FUNCTION zu drucken: paste.ubuntu.com/p/QZ35GMR5P9

    – zurückerinnern

    12. März 2021 um 7:41 Uhr

Benutzer-Avatar
Florestan

Eine andere Lösung zur Kompilierzeit, ähnlich der von matiu, aber vielleicht etwas anschaulicher, wäre die Verwendung von a static_assert verpackt in eine kleine Hilfsfunktion:

template <typename T>
void print_type_in_compilation_error(T&&)
{
    static_assert(!std::is_same<T, int>::value &&
                   std::is_same<T, int>::value,
                  "Compilation failed because you wanted to know the type; see below:");
}
// usage:
int I;
print_type_in_compilation_error(I);

Das obige gibt Ihnen eine nette Fehlermeldung (getestet in MSVC und Clang), wie in der anderen Antwort, aber der Code ist meiner Meinung nach einfacher zu verstehen.

  • Dies war für mich heute in einer Situation sehr nützlich, in der ich andere hier aufgeführte Ansätze nicht zum Laufen bringen konnte. Ich habe diesen Ansatz auch angepasst, um eine Vorlagenstruktur anstelle einer Vorlagenfunktion zu verwenden.

    – Irgendein Typ

    7. Mai 2018 um 8:43 Uhr

Benutzer-Avatar
IPC

Da Sie gesagt haben, dass Sie dies für Debugging-Zwecke benötigen würden, ist möglicherweise auch eine Laufzeitlösung akzeptabel. Und Sie haben dies als g ++ gekennzeichnet, damit Sie nicht standardkonform sein möchten.

Hier ist, was das bedeutet:

#include <cxxabi.h> // the libstdc++ used by g++ does contain this header

template <typename type>
void print(const type *addr) // you wanted a pointer
{
  char * name = abi::__cxa_demangle(typeid(*addr).name(), 0, 0, NULL);
  printf("type is: %s\n", name);
  free(name);
}
     
print(new unsigned long);    // prints "type is: unsigned long"
print(new std::vector<int>); // prints "type is: std::vector<int, std::allocator<int> >"

EDIT: Speicherleck behoben. Danke an Jesse.

Benutzer-Avatar
Andrej

Es gibt eine Boost.TypeIndex-Bibliothek.

Siehe boost::typeindex::type_id für Details.

Es ist sehr einfach zu bedienen, plattformübergreifend und eine echte Compiler-Lösung. Es funktioniert auch, wenn kein RTTI verfügbar ist. Auch die meisten Compiler werden von der Box unterstützt.

  • Beachten Sie, dass dies nur für verfügbar ist Boost >= 1.56.0.

    – BenC

    10. Oktober 2015 um 8:50 Uhr

  • Sie haben Recht, aber es ist immer noch sehr einfach zu bedienen und es ist eine echte Compiler-Lösung. Und es funktioniert auch, wenn keine RTTI-Informationen verfügbar sind. Auch die meisten Compiler werden von der Box unterstützt.

    – Andrej

    12. Oktober 2015 um 20:18 Uhr

  • Absolut, daher mein +1. Aber die nächste Information, die ich brauchte, war die mindestens erforderliche Boost-Version, da Distributionen, die ältere Versionen von Boost liefern, möglicherweise nicht über die Bibliothek verfügen (z. B. Ubuntu 12.04), was bedeutet, dass Sie in diesem Fall auf andere Lösungen zurückgreifen müssten Boost < 1.56.0 ist angeschlossen. Die zusätzlichen Informationen, die Sie hinzugefügt haben, verdienen es jedoch, in Ihrer Antwort enthalten zu sein.

    – BenC

    13. Oktober 2015 um 5:43 Uhr


Sie können C++20 verwenden concepts um eine Einschränkung zu definieren, die kein Typ erfüllen kann. Wenn Sie diese Einschränkung für ein Vorlagenargument verwenden und die Vorlage instanziieren, schlägt der Compiler fehl und gibt den abgeleiteten Typnamen aus.

void print_typename (auto) requires false {}
// Equivalent to
//   template<typename T>
//   concept unsatisfiable_c = false;
//   
//   template<unsatisfiable_c T>
//   void print_typename (T) {}

int main (int, char**) {
    int foo = 73;
    print_typename(foo);
    // error: no matching function for call to 'print_typename'
    // note: candidate template ignored: constraints not satisfied [with auto:1 = int]
    //                                                                            ^^^

    return 0;
}

Wenn dein T ist komplexer, z T=std::vector<std::pair<key_t, value_t>> oder T=void (*)(U, V const&)und Sie wollen es konkret herausfinden key_t oder Vkönnen Sie das wie folgt tun:

template<typename T>
concept unsatisfiable_c = false;

template<unsatisfiable_c key_t, typename value_t>
void print_key_t (std::vector<std::pair<key_t, value_t>>) {}

template<typename U, unsatisfiable_c V>
void print_V (void (*)(U, V const&)) {}

void foo (double, long double const&) {}

int main (int, char**) {
    std::vector<std::pair<long, char>> bar;

    print_key_t(bar);
    // error: no matching function for call to 'print_key_t'
    // note: candidate template ignored: constraints not satisfied [with key_t = long, value_t = char]

    print_V(&foo);
    // error: no matching function for call to 'print_V'
    // note: candidate template ignored: constraints not satisfied [with U = double, V = long double]

    return 0;
}

  • Beachten Sie, dass dies nur für verfügbar ist Boost >= 1.56.0.

    – BenC

    10. Oktober 2015 um 8:50 Uhr

  • Sie haben Recht, aber es ist immer noch sehr einfach zu bedienen und es ist eine echte Compiler-Lösung. Und es funktioniert auch, wenn keine RTTI-Informationen verfügbar sind. Auch die meisten Compiler werden von der Box unterstützt.

    – Andrej

    12. Oktober 2015 um 20:18 Uhr

  • Absolut, daher mein +1. Aber die nächste Information, die ich brauchte, war die mindestens erforderliche Boost-Version, da Distributionen, die ältere Versionen von Boost liefern, möglicherweise nicht über die Bibliothek verfügen (z. B. Ubuntu 12.04), was bedeutet, dass Sie in diesem Fall auf andere Lösungen zurückgreifen müssten Boost < 1.56.0 ist angeschlossen. Die zusätzlichen Informationen, die Sie hinzugefügt haben, verdienen es jedoch, in Ihrer Antwort enthalten zu sein.

    – BenC

    13. Oktober 2015 um 5:43 Uhr


Benutzer-Avatar
Gemeinschaft

Wenn Sie einen bekannten Satz von verwendeten Typen haben, instanziieren Sie die Vorlage. Wir können den in diesem älteren Thread beschriebenen Ansatz verwenden: stackoverflow.com/questions/1055452

1015590cookie-checkDrucken Sie den Namen des Vorlagentyps zur Kompilierzeit

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy