2013-08-21 13 views
5

C'è un modo semplice per forzare i compilatori a mostrarmi il tipo dedotto per un parametro di modello? Ad esempio, datoCome posso vedere il tipo dedotto per un parametro del tipo di modello?

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

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

potrei voler vedere che tipo è dedotto per T nella chiamata a f. (Penso che sia const volatile int *&, ma non sono sicuro.) O dato

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

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

potrei voler scoprire se la mia supposizione che T si deduce di essere int* nella chiamata a f è corretta.

Se esiste una soluzione di libreria di terze parti (ad esempio, da Boost), sarei interessato a conoscerla, ma mi piacerebbe anche sapere se c'è un modo semplice per forzare una diagnostica di compilazione che includa il tipo dedotto.

+5

lo vuoi durante la compilazione o in fase di esecuzione? quest'ultimo può essere fatto con '#include ' e 'typeid (T) .name()' – TemplateRex

+0

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

+0

@TemplateRex: mi piacerebbe vedere il tipo durante la compilazione. – KnowItAllWannabe

risposta

2

Per far sì che il compilatore mostri il tipo di una variabile (magari in modo approssimativo);

T parameter; 
.... 
void f(int x); 
... 
f(parameter); 

compilatore dovrebbe lamentare che "T" non può essere convertito in int, assumendo che in realtà non può. soluzione tempo

+0

Questa è un'idea interessante, ma, almeno con gcc 4.8.1 e MSVC 12, presenta delle imperfezioni. Nel primo esempio, gcc riporta il tipo due volte, una volta come 'const volatile int * const &&&' (sì, con tre e commerciali!), Una volta come 'const volatile int * const'. MSVC riporta anche il tipo due volte, una volta come 'volatile const int * const', una volta come' volatile const int * const &'. – KnowItAllWannabe

11

Link:

Sulla mia piattaforma (OS X), posso ottenere il linker di darmi queste informazioni semplicemente facendo un breve programma che è completo, meno la definizione della funzione I' m curioso:

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) 

Certo ottengo il "riferimento triplice", che dovrebbe essere interpretato come un riferimento lvalue (a causa di riferimento collasso), ed è un errore di decodifica (forse può ottenere che fissa). soluzione tempo


Run:

continuo a una funzione type_name<T>() utile per questo tipo di cose. Uno completamente portatile è possibile, ma non ottimale per me. Eccolo:

#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; 
} 

posso usarlo come:

#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); 
} 

che per me stampe out:

PVKi const& 

Questo non è terribilmente uscita amichevole. La tua esperienza potrebbe essere migliore. La mia piattaforma ABI è basata sullo Itanium ABI. E questo ABI include questa funzione:

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

posso usare questo per decodifica i simboli C++ in una forma leggibile.Una versione aggiornata type_name<T>() di approfittare di questo è:

#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; 
} 

E ora i precedenti main() stampe fuori:

int const volatile* const& 
+0

Questo è utile, grazie. Da allora ho anche scoperto che informazioni simili sono disponibili tramite '__PRETTY_FUNCTION__' sotto gcc e clang e sotto' __FUNCSIG__' sotto MSVC. Questi producono stringhe, quindi conducono a soluzioni runtime. – KnowItAllWannabe

+0

@KnowItAllWannabe a meno che non lo si utilizzi ad es. 'static_assert' – sehe

+0

@sehe: Alas,' __PRETTY_FUNCTION__' si comporta come una variabile, non una stringa letterale, quindi non può essere usata all'interno di 'static_assert'. – KnowItAllWannabe

6

ho provato quanto segue con g ++ 4.7.2 e clang ++ 3.4 (tronco 184.647); entrambi forniscono

un errore in fase di compilazione e il messaggio di errore contiene il tipo dedotto.

Non ho accesso a MSVC 12, si prega di controllare cosa succede e fornire un 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); 
} 

I messaggi di errore: g ++ 4.7.2

errore: tipo incompleto deduced_type<std::basic_string<char> > utilizzato in nome nested specificatore
errore: tipo incompleto deduced_type<std::basic_string<char>&> utilizzato in nome nested specificatore
errore: tipo incompleto deduced_type<const volatile int* const&> utilizzato in nidificato nome specificatore

e clang ++

erro R: istanziazione implicita di template definito deduced_type<std::basic_string<char> >
errore: esemplificazione implicita di template definito deduced_type<std::basic_string<char> &>
errore: esemplificazione implicita di template definito messaggi deduced_type<const volatile int *const &>

La nota/informazioni contengono anche il tipo di f con entrambi i compilatori, ad esempio

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

E 'testa a testa brutto ma funziona.

+0

+1 Sì, sono d'accordo. Anche questo funziona. –

+0

@HowardHinnant Grazie per il controllo. (Ho svalutato la tua risposta 3 ore fa.) – Ali

Problemi correlati