Можно ли вывести имя типа переменной в стандартном C++?
Проблема typeid().name() и её решение
Действительно, typeid().name() возвращает "искажённые" (mangled) имена типов. Это внутреннее представление компилятора, которое не предназначено для чтения человеком. В разных компиляторах эти имена выглядят по-разному: MSVC может показать "int", а GCC/Clang — "i". К счастью, есть несколько способов получить нормальные имена.
Способ 1: Использование макроса и шаблона (рекомендуется)
Лучший кроссплатформенный метод — написать простую функцию-шаблон, которая использует __PRETTY_FUNCTION__ (GCC/Clang) или __FUNCSIG__ (MSVC). Эти макросы содержат полную сигнатуру функции, включая имя типа.
#include <iostream>
#include <string>
#include <type_traits>
// Функция для получения имени типа в читаемом виде
template <typename T>
constexpr std::string_view type_name() {
#if defined(__clang__) || defined(__GNUC__)
// Для GCC и Clang
return __PRETTY_FUNCTION__;
#elif defined(_MSC_VER)
// Для MSVC
return __FUNCSIG__;
#endif
}
// Утилита для извлечения чистого имени
template <typename T>
std::string type_name_clean() {
std::string_view raw = type_name<T>();
// Ищем позицию имени типа в строке сигнатуры
auto start = raw.find('=');
if (start == std::string_view::npos) start = 0;
else start += 2; // пропускаем "= "
auto end = raw.find(';', start);
if (end == std::string_view::npos) end = raw.find(']', start);
if (end == std::string_view::npos) end = raw.size() - 1;
return std::string(raw.substr(start, end - start));
}
int main() {
int a = 5;
const char* str = "hello";
auto x = a + 3.14;
std::cout << type_name_clean<decltype(a)>() << std::endl; // "int"
std::cout << type_name_clean<decltype(str)>() << std::endl; // "const char*"
std::cout << type_name_clean<decltype(x)>() << std::endl; // "double"
return 0;
}
Способ 2: Использование Boost.TypeIndex
Если вы используете Boost, есть готовое решение:
#include <boost/type_index.hpp>
#include <iostream>
int main() {
int a = 5;
auto b = a + 3.14f;
std::cout << boost::typeindex::type_id<decltype(a)>().pretty_name() << std::endl; // "int"
std::cout << boost::typeindex::type_id<decltype(b)>().pretty_name() << std::endl; // "float"
return 0;
}
Как работает первый способ?
- __PRETTY_FUNCTION__ — в GCC/Clang содержит полную сигнатуру функции, например:
constexpr std::string_view type_name() [with T = int; ...] - __FUNCSIG__ — в MSVC делает то же самое:
class std::basic_string_view<char,struct std::char_traits<char> > __cdecl type_name<int>(void) - Мы извлекаем имя типа, находя часть после "T = " (или аналогичного разделителя).
Важно!
В C++23 появился оператор std::is_same_v и улучшенный std::source_location, но для получения строкового представления типа всё ещё нет стандартного способа. Начиная с C++26, возможно, добавится std::type_info::name() с читаемыми именами, но пока приходится использовать трюки с макросами.
Для простого отладочного вывода можно использовать более короткую версию:
#define TYPE_NAME(x) []() { \
std::cout << #x << " is " << type_name_clean<decltype(x)>() << std::endl; \
}()
int main() {
int a = 5;
TYPE_NAME(a); // выведет: "a is int"
}
<<Альтернативный подход: ручное декодирование typeid().name()
Если вы не хотите использовать макросы или Boost, можно написать функцию для декодирования "искажённых" имён. Это работает только для GCC/Clang, так как MSVC использует другую схему:
#include <iostream>
#include <typeinfo>
#include <cxxabi.h> // только для GCC/Clang
std::string demangle(const char* mangled_name) {
int status = 0;
char* demangled = abi::__cxa_demangle(mangled_name, nullptr, nullptr, &status);
std::string result = (status == 0) ? demangled : mangled_name;
std::free(demangled);
return result;
}
int main() {
auto x = 42.5f;
std::cout << demangle(typeid(x).name()) << std::endl; // "float"
return 0;
}
Недостатки этого метода
- Работает только на GCC/Clang (требуется
cxxabi.h). - Не подходит для MSVC (там нужно использовать
UnDecorateSymbolNameиз Windows API). - Медленнее, чем использование макросов, так как требует динамической аллокации.
Для простых проектов этот способ сойдёт, но для серьёзной разработки лучше использовать первый вариант из основного ответа.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги