c++中如何打印未知类型对象的类型

在 C++ 中要打印未知类型对象的类型名称,可以通过以下方法实现:

目录

[方法一:使用 typeid 和 name()(需包含 )](#方法一:使用 typeid 和 name()(需包含 ))

使用示例:

问题与改进:

[方法二:编译时类型名称(C++17 起)](#方法二:编译时类型名称(C++17 起))

使用示例:

[方法三:使用 Boost 库(跨平台)](#方法三:使用 Boost 库(跨平台))

对比总结:

注意事项:

完整示例(支持跨平台反修饰):


方法一:使用 typeidname()(需包含 <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 表示 intd 表示 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 库 输出美观、跨平台 需要额外安装依赖库

注意事项:

  1. 多态类型typeid 对多态类型会返回动态类型

    cpp 复制代码
    class Base { virtual void foo() {} }; // 必须包含虚函数
    class Derived : public Base {};
    
    Base* obj = new Derived;
    std::cout << typeid(*obj).name(); // 输出 Derived 的类型
  2. 类型修饰

    cpp 复制代码
    const int& x = 42;
    printType(x);  // 可能输出 "i" 而非 "const int&"
  3. 平台兼容性

    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;
}
相关推荐
catchadmin13 小时前
PHP True Async RFC 被拒——原生异步离 PHP 还有多远?
开发语言·php
J***793913 小时前
PHP在电商中的Magento
开发语言·php
恒者走天下14 小时前
秋招落定,拿到满意的offer,怎么提高自己实际的开发能力,更好的融入团队
c++
做怪小疯子14 小时前
LeetCode 热题 100——矩阵——旋转图像
算法·leetcode·矩阵
努力学习的小廉14 小时前
我爱学算法之—— BFS之最短路径问题
算法·宽度优先
python零基础入门小白14 小时前
【万字长文】大模型应用开发:意图路由与查询重写设计模式(从入门到精通)
java·开发语言·设计模式·语言模型·架构·大模型应用开发·大模型学习
天若有情67314 小时前
【c++】手撸C++ Promise:从零实现通用异步回调组件,支持链式调用+异常安全
开发语言·前端·javascript·c++·promise
无心水14 小时前
【Python实战进阶】1、Python高手养成指南:四阶段突破法从入门到架构师
开发语言·python·django·matplotlib·gil·python实战进阶·python工程化实战进阶
高山上有一只小老虎14 小时前
构造A+B
java·算法
学困昇14 小时前
C++中的异常
android·java·c++