2012-12-30 7 views
12

Poiché typeid(T).name() non restituisce il nome comprensibile dell'uomo del tipo, non ci aiuta molto se si desidera stampare il nome degli argomenti del modello in qualche classe modello, specialmente quando eseguiamo il debug. Spesso ci sentiamo come scrivere questo in debug:Tipi di stampa e modello di classe insieme a tutti gli argomenti del modello

print<Args...>(cout); //dump the names of all types to stdout! 

Così sto scrivendo utilità pretty-print, che mi dà il nome del modello di classe. Beh, è ​​più facile capire attraverso qualche esempio dell'uso:

print<int>(cout);    //prints int 
print<int, double, char>(cout); //prints int, double, char 
print<std::string>(cout);  //prints std::basic_string<char, .. etc> 
print<std::wstring>(cout);  //prints std::basic_string<wchar_t, .. etc> 
print<X<int,Y<int>>>(cout);  //prints X<int, Y<int>> 

Internamente, sto utilizzando un modello di classe chiamata template_name che mi riporta "Y" quando passo Y<int> ad esso come argomento di template. Ecco come è parzialmente specializzato per ogni modello di classe utente.

#define DEFINE_TEMPLATE_NAME(template_type) \ 
template<typename ... Ts>\ 
struct template_name<template_type<Ts...>>\ 
{\ 
    static const char* name()\ 
    {\ 
     return #template_type;\ 
    }\ 
}; 

E l'utente è necessario per utilizzare questa macro per registrare la sua classe template come:

DEFINE_TEMPLATE_NAME(std::basic_string); 
DEFINE_TEMPLATE_NAME(std::vector); 
DEFINE_TEMPLATE_NAME(X); //X is a class template 
DEFINE_TEMPLATE_NAME(Y); //Y is a class template 

Questo funziona perché la specializzazione template_name<template_type<Ts...>> è un modello di classe variadic su tipi solo, il che significa che mi restituirebbe il nome del modello di classe finchè tutti i parametri del modello sono tipi. E 'anche in grado di stampare funzione-tipo e membro-funzione-tipi così:

typedef void fun(int,int); 

//lets use snl::name() which returns name instead of printing! 
std::cout << snl::name<fun>(); //prints : void(int,int) 
std::cout << snl::name<fun*>(); //prints : void(*)(int,int) 

Si prega di vedere the working code here con altri piccoli dettagli. Funziona benissimo finora.

Ma ora sto migliorando su questo, e si desidera aggiungere il supporto per i non-tipi Tempate argomenti e argomenti template misti così:

template<int...> 
struct Z{}; 

//non-type template arguments : 1,2,3 
snd::print<Z<1,2,3>>(cout); //should print Z<1,2,3> 

//mixed template arguments : int, 100 
snd::print<std::array<int,100>>(cout); //should print std::array<int,100> 

Come potrei farlo? Come posso ottenere genericamente il nome di tale modello di classe e i suoi argomenti?

+5

GCC ha un demangler che stampa nomi di classi template piuttosto utili ... –

+0

@KerrekSB: Sì, ma non è standard. Voglio qualcosa che funzioni ovunque. – Nawaz

risposta

6

Mi dispiace, questa è una "risposta negativa" (sto inviando la tua domanda), ma temo che non puoi farlo. Anche considerando solo le classi template che accettano liste omogenee di parametri non-tipo (ad es template<int, int>, template<char, char, char>, ecc), si avrebbe bisogno di una specializzazione di questo genere:

template<typename T> 
struct single_type 
{ 
    // ... 
}; 

template<typename U, template<U...> class C, U... Us> 
struct single_type<C<Us...>> 
{ 
    // ... 
}; 

Questa specializzazione è legale, ma inutile, perché il tipo di argomento U non può mai essere dedotto. È possibile definire specializzazioni dedicate per liste uniformi di letterali dei tipi più comuni (int..., char..., ecc.), Ma sarebbe comunque impossibile coprire sequenze di tipi eterogenei, per non parlare di sequenze di argomenti misti.

Temo che dovremo aspettare che il C++ supporti la riflessione per ottenere quello che stai cercando.