Возможно ли вывести тип переменной в стандартном C++?
Описание проблемы:
Я пытаюсь вывести тип переменной в C++, но, вместо ожидаемого результата, не могу добиться нужного вывода. Например, у меня есть следующий код:
int a = 12;
cout << typeof(a) << endl;
Я ожидаю, что результат будет:
int
Однако компилятор выдает ошибку, так как typeof
не является допустимым оператором в стандартном C++. Как я могу получить тип переменной a
во время выполнения программы?
5 ответ(ов)
Попробуйте:
#include <typeinfo>
// …
std::cout << typeid(a).name() << '\n';
Вам, возможно, придется активировать RTTI в настройках компилятора для этого, чтобы это сработало. Также имейте в виду, что вывод будет зависеть от компилятора. Это может быть как простое имя типа, так и символ с манглированием имени или что-то посередине.
Очень некрасиво, но рабочий вариант, если вам нужны только данные на этапе компиляции (например, для отладки):
auto testVar = std::make_tuple(1, 1.0, "abc");
decltype(testVar)::foo = 1;
Возвращает:
Компиляция завершена с ошибками:
source.cpp: В функции 'int main()':
source.cpp:5:19: ошибка: 'foo' не является членом 'std::tuple<int, double, const char*>'
Не забудьте подключить <typeinfo>
Я полагаю, вы говорите о определении типа во время выполнения (runtime type identification). Вы можете добиться этого следующим образом:
#include <iostream>
#include <typeinfo>
using namespace std;
int main() {
int i;
cout << typeid(i).name();
return 0;
}
В этом примере мы используем typeid
для получения информации о типе переменной i
. Не забудьте подключить заголовочный файл <typeinfo>
для правильной работы этой функции.
Обратите внимание, что имена, сгенерированные с помощью механизма RTTI в C++, не являются переносимыми. Например, для класса
MyNamespace::CMyContainer<int, test_MyNamespace::CMyObject>
будут получены следующие имена:
// MSVC 2003:
class MyNamespace::CMyContainer[int,class test_MyNamespace::CMyObject]
// G++ 4.2:
N8MyNamespace8CMyContainerIiN13test_MyNamespace9CMyObjectEEE
Таким образом, вы не сможете использовать эту информацию для сериализации. Тем не менее, свойство typeid(a).name() все еще может быть полезным для логирования или отладки.
Как упоминалось, typeid().name()
может возвращать "замангленный" (mangled) имя. В GCC (и некоторых других компиляторах) вы можете обойти это с помощью следующего кода:
#include <cxxabi.h>
#include <iostream>
#include <typeinfo>
#include <cstdlib>
namespace some_namespace { namespace another_namespace {
class my_class { };
} }
int main() {
typedef some_namespace::another_namespace::my_class my_type;
// замангленное имя
std::cout << typeid(my_type).name() << std::endl;
// развязанное имя
int status = 0;
char* demangled = abi::__cxa_demangle(typeid(my_type).name(), 0, 0, &status);
switch (status) {
case -1: {
// не удалось выделить память
std::cout << "Не удалось выделить память" << std::endl;
return -1;
} break;
case -2: {
// некорректное имя по правилам манглинга C++ ABI
std::cout << "Некорректное имя" << std::endl;
return -1;
} break;
case -3: {
// некорректный аргумент
std::cout << "Некорректный аргумент для demangle()" << std::endl;
return -1;
} break;
}
std::cout << demangled << std::endl;
free(demangled);
return 0;
}
Этот код позволяет вам получить "размангленное" имя типа, что может быть полезно для улучшения читаемости вывода вашей программы.
Почему следует использовать указатель вместо самого объекта?
Что такое std::move() и когда его следует использовать?
Какова разница между 'typedef' и 'using'?
В чем разница между constexpr и const?
Когда действительно стоит использовать noexcept?