在 C++ 中要打印未知类型对象的类型名称,可以通过以下方法实现:
目录
[方法一:使用 typeid 和 name()(需包含 )](#方法一:使用 typeid 和 name()(需包含 ))
[方法二:编译时类型名称(C++17 起)](#方法二:编译时类型名称(C++17 起))
[方法三:使用 Boost 库(跨平台)](#方法三:使用 Boost 库(跨平台))
方法一:使用 typeid
和 name()
(需包含 <typeinfo>
)
cpp
#include <iostream>
#include <typeinfo>
template <typename T>
void printType(const T& obj) {
std::cout << "类型名称: " << typeid(obj).name() << std::endl;
}
使用示例:
cpp
int main() {
auto x = 3.14;
printType(x); // 输出类似 "d"(GCC)或 "double"(MSVC)
return 0;
}
问题与改进:
-
编译器差异:
-
GCC/Clang 会返回名称修饰的字符串(如
i
表示int
,d
表示double
) -
MSVC 会直接返回可读名称(如
int
)
-
-
Demangling(反修饰):
cpp#include <cxxabi.h> // GCC/Clang 专用 template <typename T> void printHumanReadableType(const T& obj) { int status; char* name = abi::__cxa_demangle(typeid(obj).name(), 0, 0, &status); std::cout << "可读类型: " << (status == 0 ? name : "未知类型") << std::endl; free(name); }
方法二:编译时类型名称(C++17 起)
cpp
#include <string_view>
template <typename T>
constexpr std::string_view type_name() {
#if defined(__clang__)
return __PRETTY_FUNCTION__;
#elif defined(__GNUC__)
return __PRETTY_FUNCTION__;
#elif defined(_MSC_VER)
return __FUNCSIG__;
#endif
}
template <typename T>
void printTypeAtCompileTime() {
constexpr auto prefix = sizeof("auto type_name() [T = ") - 1;
constexpr auto suffix = sizeof("]") - 1;
constexpr auto name = type_name<T>();
std::cout << "编译时类型: "
<< name.substr(prefix, name.size() - prefix - suffix)
<< std::endl;
}
使用示例:
cpp
printTypeAtCompileTime<std::vector<int>>();
// 输出类似 "std::vector<int, std::allocator<int>>"
方法三:使用 Boost 库(跨平台)
cpp
#include <boost/type_index.hpp>
template <typename T>
void printTypeWithBoost(const T& obj) {
using boost::typeindex::type_id_with_cvr;
std::cout << "Boost 类型: "
<< type_id_with_cvr<T>().pretty_name()
<< std::endl;
}
对比总结:
方法 | 优点 | 缺点 |
---|---|---|
typeid |
简单直接 | 需要处理名称修饰 |
编译时方法 | 无需运行时开销 | 依赖编译器特定宏 |
Boost 库 | 输出美观、跨平台 | 需要额外安装依赖库 |
注意事项:
-
多态类型 :
typeid
对多态类型会返回动态类型cppclass Base { virtual void foo() {} }; // 必须包含虚函数 class Derived : public Base {}; Base* obj = new Derived; std::cout << typeid(*obj).name(); // 输出 Derived 的类型
-
类型修饰:
cppconst int& x = 42; printType(x); // 可能输出 "i" 而非 "const int&"
-
平台兼容性:
cpp#if defined(__GNUC__) && !defined(__clang__) // GCC 专用处理 #elif defined(_MSC_VER) // MSVC 专用处理 #endif
完整示例(支持跨平台反修饰):
cpp
#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
template <typename T>
std::string demangle() {
int status = -1;
const char* name = typeid(T).name();
char* demangled = abi::__cxa_demangle(name, NULL, NULL, &status);
std::string result = (status == 0) ? demangled : name;
free(demangled);
return result;
}
int main() {
const std::vector<double> vec;
std::cout << "Demangled type: " << demangle<decltype(vec)>() << std::endl;
// 输出: std::vector<double, std::allocator<double> >
return 0;
}