2013-08-21 7 views
5

Gibt es eine einfache Möglichkeit, Compiler zu zwingen, den Typ zu zeigen, der für einen Template-Parameter abgeleitet wurde? Zum Beispiel gegebenWie kann ich den für einen Template-Typ-Parameter abgeleiteten Typ sehen?

template<typename T> 
void f(T&& parameter); 

const volatile int * const pInt = nullptr; 
f(pInt); 

könnte ich möchte sehen, welche Art für T in dem Aufruf von f abgeleitet wird. (Ich glaube, es ist const volatile int *&, aber ich bin mir nicht sicher.) Oder gegeben

template<typename T> 
void f(T parameter); 

int numbers[] = { 5, 4, 3, 2, 1 }; 
f(numbers); 

könnte ich möchte herausfinden, ob meine Vermutung, dass T abgeleitet wird int* im Aufruf f sein korrekt ist.

Wenn es eine Drittanbieter-Bibliothekslösung gibt (z. B. von Boost), würde mich das interessieren, aber ich würde auch gerne wissen, ob es eine einfache Möglichkeit gibt, eine Kompilierungsdiagnose zu erzwingen der abgeleitete Typ.

+5

möchten Sie dies während der Kompilierung oder zur Laufzeit? letzteres kann mit '#include ' und 'typeid (T) .name()' – TemplateRex

+0

'std :: is_same :: value'? – Rapptz

+0

@TemplateRex: Ich möchte den Typ während der Kompilierung sehen. – KnowItAllWannabe

Antwort

2

Um den Compiler zu bekommen, um den Typ einer Variablen zu zeigen (vielleicht in einer Runde um);

Compiler sollte beschweren, dass "T" nicht in int konvertiert werden kann, vorausgesetzt, dass es tatsächlich nicht möglich ist.

+0

Dies ist eine interessante Idee, aber, zumindest mit gcc 4.8.1 und MSVC 12, hat es Mängel. Im ersten Beispiel meldet gcc den Typ zweimal, einmal als const volatile int const &&& (ja, mit drei kaufmännischen Und-Zeichen!), Einmal als const volatile int const. MSVC meldet den Typ auch zweimal, einmal als 'flüchtig const int const', einmal als flüchtig const int const &. – KnowItAllWannabe

11

Link-Zeitlösung:

Auf meiner Plattform (O X), kann ich den Linker hol mir, indem einfach ein kurzes Programm, diese Informationen zu geben, die abgeschlossen ist, minus der Definition der Funktion I‘ m gespannt:

template<typename T> 
void f(T&& parameter); // purposefully not defined 

int 
main() 
{ 
    const volatile int * const pInt = nullptr; 
    f(pInt); 
} 

Undefined symbols for architecture x86_64: 
    "void f<int const volatile* const&>(int const volatile* const&&&)", referenced from: 
     _main in test-9ncEvm.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Zwar habe ich die „triple Referenz“, die als L-Wert-Referenz (wegen Referenz Kollabieren) interpretiert werden sollen, und ist ein Demangling Bug (vielleicht kann ich das fest).


Laufzeit Lösung:

Ich halte eine type_name<T>() Funktion praktisch für diese Art der Sache. Ein komplett portabler ist möglich, aber für mich suboptimal. Hier ist sie:

#include <type_traits> 
#include <typeinfo> 
#include <string> 

template <typename T> 
std::string 
type_name() 
{ 
    typedef typename std::remove_reference<T>::type TR; 
    std::string r = typeid(TR).name(); 
    if (std::is_const<TR>::value) 
     r += " const"; 
    if (std::is_volatile<TR>::value) 
     r += " volatile"; 
    if (std::is_lvalue_reference<T>::value) 
     r += "&"; 
    else if (std::is_rvalue_reference<T>::value) 
     r += "&&"; 
    return r; 
} 

Ich mag es verwenden können:

#include <iostream> 

template<typename T> 
void f(T&& parameter) 
{ 
    std::cout << type_name<T>() << '\n'; 
} 

int 
main() 
{ 
    const volatile int * const pInt = nullptr; 
    f(pInt); 
} 

die für mich ausdruckt:

PVKi const& 

Das ist nicht besonders freundlich Ausgang ist. Deine Erfahrung ist vielleicht besser. Meine Plattform ABI basiert auf der Itanium ABI. Und das ABI enthält diese Funktion:

namespace abi 
{ 
    extern "C" 
    char* 
    __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status); 
} 

Ich kann diese verwenden C++ Symbole in eine für Menschen lesbare Form demangle.Ein type_name<T>() aktualisiert nutzen hierfür ist:

#include <type_traits> 
#include <typeinfo> 
#include <string> 
#include <memory> 
#include <cstdlib> 
#include <cxxabi.h> 

template <typename T> 
std::string 
type_name() 
{ 
    typedef typename std::remove_reference<T>::type TR; 
    std::unique_ptr<char, void(*)(void*)> own 
     (
      abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, nullptr), 
      std::free 
     ); 
    std::string r = own != nullptr ? own.get() : typeid(TR).name(); 
    if (std::is_const<TR>::value) 
     r += " const"; 
    if (std::is_volatile<TR>::value) 
     r += " volatile"; 
    if (std::is_lvalue_reference<T>::value) 
     r += "&"; 
    else if (std::is_rvalue_reference<T>::value) 
     r += "&&"; 
    return r; 
} 

Und nun die vorherigen main() druckt:

int const volatile* const& 
+0

Das ist nützlich, danke. Ich habe auch gefunden, dass ähnliche Informationen über '__PRETTY_FUNCTION__' unter gcc und clang und unter' __FUNCSIG__' unter MSVC verfügbar sind. Diese erzeugen Strings, also führen sie zu Runtime-Lösungen. – KnowItAllWannabe

+0

@KnowItAllWannabe, es sei denn, Sie verwenden es z. 'static_assert' – sehe

+0

@sehe: Ach,' __PRETTY_FUNCTION__' verhält sich wie eine Variable, kein String-Literal, also kann es nicht in 'static_assert' verwendet werden. – KnowItAllWannabe

6

ich das Folgende mit g versucht haben ++ 4.7.2 und Klirren ++ 3.4 (Stamm 184647); Beide geben

einen Fehler bei der Kompilierung und die Fehlermeldung enthält den abgeleiteten Typ.

Ich habe keinen Zugang zu MSVC 12, bitte überprüfen Sie, was passiert und geben Sie Feedback.

#include <string> 

template <typename T> 
struct deduced_type; 


template<typename T> 
void f(T&&) { 

    deduced_type<T>::show; 
} 

int main() { 

    f(std::string()); // rvalue string 

    std::string lvalue; 

    f(lvalue); 

    const volatile int * const pInt = nullptr; 

    f(pInt); 
} 

die Fehlermeldungen: g ++ 4.7.2

Fehler: unvollständiger Typ deduced_type<std::basic_string<char> > in verschachteltem namen Spezifizierer
Fehler verwendet: unvollständiger Typ deduced_type<std::basic_string<char>&> in verschachteltem namen Spezifizierer
Fehler verwendet: deduced_type<const volatile int* const&> unvollständiger Typ verwendete in verschachtelter name-Bezeichner

und Klirren ++

erro r: implizite Instanziierung undefiniert Vorlage deduced_type<std::basic_string<char> >
Fehler: implizite Instanziierung undefiniert Vorlage deduced_type<std::basic_string<char> &>
Fehler: implizite Instanziierung undefiniert Vorlage deduced_type<const volatile int *const &>

Die Note/Info-Meldungen auch die Art des f mit beiden Compiler enthalten, zum Beispiel

In Instanziierung void f(T&&) [with T = std::basic_string<char>]

Es ist stumpf hässlich, aber funktioniert.

+0

+1 Ja, ich stimme zu. Das funktioniert auch. –

+0

@HowardHinnant Danke für die Überprüfung. (Ich habe Ihre Antwort vor 3 Stunden aktualisiert.) – Ali

Verwandte Themen