2016-03-11 21 views
19

Vorrei utilizzare il nome di un tipo in fase di compilazione. Per esempio, supponiamo che ho scritto:Posso ottenere nomi di tipo C++ in modo constexpr?

constexpr size_t my_strlen(const char* s) 
{ 
     const char* cp = s; 
     while(*cp != '\0') { cp++; }; 
     return cp - s; 
} 

e ora voglio avere:

template <typename T> 
constexpr auto type_name_length = my_strlen(typeid(T).name()); 

Ma, ahimè, typeid(T).name() è solo const char*, non constexpr ... c'è qualche altro modo constexpr per ottenere il nome di un tipo?

+0

Cosa intendi fare con 'type_name_length ' ne hai bisogno al momento della compilazione? I compilatori sono piuttosto bravi a valutare semplicemente 'strlen()' e a darti una costante se possibile. – Barry

+0

@Barry: Volevo solo un MCVE qui, quindi ho inventato un uso sintetico. – einpoklum

+0

@einpoklum Questo è buono; ma aggiungere un commento dicendo che nella domanda (questo è semplicemente un MCVE, sto davvero provando a X) è anche buono. – Yakk

risposta

50

Beh, si potrebbe, una sorta di, ma probabilmente non del tutto portatile:

struct string_view 
{ 
    char const* data; 
    std::size_t size; 
}; 

inline std::ostream& operator<<(std::ostream& o, string_view const& s) 
{ 
    return o.write(s.data, s.size); 
} 

template<class T> 
constexpr string_view get_name() 
{ 
    char const* p = __PRETTY_FUNCTION__; 
    while (*p++ != '='); 
    for (; *p == ' '; ++p); 
    char const* p2 = p; 
    int count = 1; 
    for (;;++p2) 
    { 
     switch (*p2) 
     { 
     case '[': 
      ++count; 
      break; 
     case ']': 
      --count; 
      if (!count) 
       return {p, std::size_t(p2 - p)}; 
     } 
    } 
    return {}; 
} 

E si può definire il desiderato type_name_length come:

template <typename T> 
constexpr auto type_name_length = get_name<T>().size; 

DEMO (lavora per clang & g ++)

+2

Qualcosa di simile potrebbe essere implementato su MSVC con '__FUNCSIG__'. – melak47

+2

Funziona solo per C++ 14 o versioni successive, ovviamente. – einpoklum

+0

Ho trovato [questo sito] (http://rextester.com/l/cpp_online_compiler_visual) e testato '__FUNCSIG__'. Sembra emettere i tipi completamente sostituiti/rilegati, come se la funzione fosse esplicitamente istanziata, al contrario dell'output ibrido di GCC. Ad esempio: 'void __cdecl foo (const double &)', che mi sembra meno utile a colpo d'occhio. (GCC fa ancora qualche strana distinzione tra i tipi dipendenti e quelli liberi, o forse dedotti rispetto ai tipi calcolati, quando si eseguono sostituzioni.) Penso che la riflessione sia altamente sottovalutata e sottostimata, esp. con Concepts finora oltre l'orizzonte ... –