2016-03-11 8 views
19

Ich möchte den Namen eines Typs zur Kompilierzeit verwenden. Angenommen, die ich geschrieben habe:Kann ich C++ Typnamen in einem conexpr Weg erhalten?

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

und jetzt will ich muß:

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

Aber leider typeid(T).name() ist nur const char*, constexpr nicht ... gibt es einen anderen, constexpr Weg um den Namen eines Typs zu bekommen?

+0

Was haben Sie mit 'type_name_length ' zu tun, dass Sie es zur Kompilierzeit brauchen? Compiler sind ziemlich gut darin, nur 'strlen()' zu bewerten und Ihnen eine Konstante zu geben, wenn das möglich ist. – Barry

+0

@Barry: Ich wollte nur einen MCVE hier, also habe ich einen synthetischen Gebrauch gemacht. – einpoklum

+0

@einpoklum Das ist gut; aber das Hinzufügen eines Kommentars, dass in der Frage (das ist nur ein MCVE, ich versuche wirklich X) ist auch gut. – Yakk

Antwort

50

Nun, könnte man, irgendwie, aber wahrscheinlich nicht ganz tragbar:

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

Und Sie können definieren Sie die gewünschte type_name_length als:

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

DEMO (arbeitet für Klirren & g ++)

+2

Etwas ähnliches könnte auf MSVC mit '__FUNCSIG__' implementiert werden. – melak47

+2

Funktioniert natürlich nur für C++ 14 oder später. – einpoklum

+0

Ich fand [diese Seite] (http://rextester.com/l/cpp_online_compiler_visual) und testete "__FUNCSIG__". Es scheint die vollständig substituierten/gebundenen Typen zu emittieren, so als ob die Funktion explizit instanziiert wäre, im Gegensatz zur hybriden Ausgabe von GCC. Zum Beispiel: 'void __cdecl foo (const double &)', das auf einen Blick weniger hilfreich aussieht. (GCC macht immer noch eine seltsame Unterscheidung zwischen abhängigen vs. freien Typen oder vielleicht abgeleiteten vs. berechneten Typen, wenn Substitutionen durchgeführt werden.) Ich denke, Reflexion wird stark unterschätzt und unter-unterstützt, besonders bei mit Konzepten so weit über den Horizont ... –