2016-03-11 14 views
19

Chciałbym użyć nazwy typu w czasie kompilacji. Na przykład załóżmy, że mam napisane:Czy mogę uzyskać nazwy typu C++ w sposób constexpr?

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

i teraz chcę mieć:

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

Ale niestety, to tylko const char*typeid(T).name(), nie constexpr ... czy jest jakiś inny, constexpr sposób uzyskać nazwę typu?

+0

Co masz zamiar zrobić z 'type_name_length ', że potrzebujesz jej podczas kompilacji? Kompilatory są całkiem dobre, jeśli chodzi o ocenę 'strlen()' i daje stałą wartość, jeśli jest to możliwe. – Barry

+0

@ Barry: Chciałem tylko MCVE tutaj, więc zrobiłem syntetyczny użytek. – einpoklum

+0

@einpoklum To jest dobre; ale dodanie komentarza mówiącego, że w pytaniu (to jest tylko MCVE, naprawdę próbuję X) jest również dobre. – Yakk

Odpowiedz

50

Cóż, można, rodzaj, ale prawdopodobnie nie całkiem przenośny:

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

I można określić żądany type_name_length jak:

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

DEMO (pracuje dla dzyń & g ++)

+2

Coś podobnego można zaimplementować w MSVC za pomocą '__FUNCSIG__'. – melak47

+2

Działa tylko dla C++ 14 lub nowszego, oczywiście. – einpoklum

+0

Znalazłem [tę stronę] (http://rextester.com/l/cpp_online_compiler_visual) i przetestowałem '__FUNCSIG__'. Wydaje się, że emituje w pełni podstawione/związane typy, tak jakby funkcja była jawnie tworzona, w przeciwieństwie do wyjścia hybrydowego GCC. Na przykład: 'void __cdecl foo (const double &)', co wydaje mi się mniej pomocne na pierwszy rzut oka. (GCC wciąż dokonuje dziwnego rozróżnienia między rodzajami zależnymi a wolnymi, lub może wyprowadzonymi w porównaniu z typami obliczonymi, podczas dokonywania zastępstw). Myślę, że refleksja jest wysoce niedoceniana i słabo wspierana, szczególnie. z koncepcjami jak dotąd na horyzoncie ... –

Powiązane problemy