2016-03-11 9 views
19

Я хотел бы использовать имя типа во время компиляции. Например, предположим, что я написал:Могу ли я получить имена типов C++ в режиме constexpr?

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

и теперь я хочу, чтобы иметь:

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

Но увы, typeid(T).name() просто const char*, не constexpr ... есть другие, constexpr путь получить имя типа?

+0

Что вы намерены делать с 'type_name_length ' что вам нужно во время компиляции? Компиляторы довольно хорошо оценивают 'strlen()' и дают вам константу, если это возможно. – Barry

+0

@Barry: Мне просто нужен MCVE здесь, поэтому я придумал синтетическое использование. – einpoklum

+0

@einpoklum Это хорошо; но добавив комментарий, говорящий, что в вопросе (это всего лишь MCVE, я действительно пытаюсь X) тоже хорошо. – Yakk

ответ

50

Ну, вы могли бы, своего рода, но, вероятно, не совсем портативный:

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

И вы можете определить желаемый type_name_length как:

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

DEMO (работает лязгом & г ++)

+2

Нечто подобное может быть реализовано на MSVC с '__FUNCSIG__'. – melak47

+2

Работает только для C++ 14 или новее, конечно. – einpoklum

+0

Я нашел [этот сайт] (http://rextester.com/l/cpp_online_compiler_visual) и протестировал '__FUNCSIG__'. По-видимому, он испускает полностью замещенные/связанные типы, как если бы функция была явно инстанцирована, в отличие от гибридного выхода GCC. Например: 'void __cdecl foo (const double &)', который выглядит менее полезным для меня с первого взгляда. (GCC по-прежнему делает странное различие между зависимыми и свободными типами или может быть выведено по сравнению с вычисленными типами при выполнении замещений.) Я думаю, что отражение сильно недооценено и недоподдерживается, особенно. с концепциями до сих пор за горизонтом ... –