C++获取类型名称的技巧

3to4 / 2024-07-15 / 原文

C++获取类型名称的技巧

在某些情况下,我们需要明确知道编译器推导出的类型,特别是复杂类型。这些类型信息对于调试、优化和确保代码正确性非常重要。

技巧1:在编译期确定类型

主要用于模板编程和泛型编程时。

在编译期间确定类型的一种方法是通过引发编译错误,查看编译器的错误信息

示例:如何通过引发编译错误查看类型

template<typename T>
class TypeDisplayer; // 提供一个没有定义的辅助模板类,用于引发编译时模板实例化错误

int main() {
    auto a = 10;
    auto b = &a;
    
    TypeDisplayer<decltype(a)> aType;
    TypeDisplayer<decltype(b)> bType;
}

在这种情况下,编译器会报告错误,显示 ab 的实际类型。这种方法特别适合在开发过程中快速查看类型推导结果,而不需要额外的工具:

error: aggregate 'TypeDisplayer<int> aType' has incomplete type and cannot be defined
error: aggregate 'TypeDisplayer<int *> bType' has incomplete type and cannot be defined

这告诉我们 a 的类型是 intb 的类型是 int*

技巧2:在运行时确定类型

主要用于动态类型系统或多态性场景中。

typeid 操作符生成一个 std::type_info 对象,而 std::type_infoname 成员函数会返回一个描述类型名称的字符串。

示例:使用 typeidstd::type_info::name 可以在运行时获取类型信息

#include <iostream>
#include <typeinfo>

int main() {
    int x = 42;
    const int* y = &x;

    std::cout << "x 的类型: " << typeid(x).name() << std::endl;
    std::cout << "y 的类型: " << typeid(y).name() << std::endl;

    return 0;
}
类型信息:
x 的类型: i
y 的类型: PKi

在这个输出中:

  • i 代表 int
  • PKi 代表 pointer to konst const int(常量整数指针)

你可以使用 GNU 提供的 c++filt 工具来demangle这些修饰类型名称,使其更易于理解。

技巧3:使用 Boost.TypeIndex 提供更准确的类型信息

typeidstd::type_info::name 在某些情况下可能不会显示完整的类型信息,特别是在处理引用和 const 限定符时。使用 Boost.TypeIndex 库可以提供更准确的类型信息,保留所有的类型限定符:

#include <boost/type_index.hpp>
#include <iostream>
#include <vector>

template<typename T>
void process(const T& param) {
    using boost::typeindex::type_id_with_cvr;
    std::cout << "T = " << type_id_with_cvr<T>().pretty_name() << '\n';
    std::cout << "param = " << type_id_with_cvr<decltype(param)>().pretty_name() << '\n';
}

std::vector<int> generateVector() {
    return {1, 2, 3};
}

int main() {
    const auto myVector = generateVector();
    if (!myVector.empty()) {
        process(&myVector[0]);
    }
    return 0;
}