掘金 后端 ( ) • 2024-04-29 15:45

最近在stackoverflow看到一个问题: Is it possible to print a variable's type in standard C++? 觉得挺有意思, 整理下供大家阅读.

本文介绍了获取对象类型的两个:

  • __typeofObj(obj)获取求解对象定义时的类型
    int&& r = 2;
    __cs(__typeofObj(r));   // r=int&&
  • __typeofExpr(obj)获取求解对象做为表达式时的类型值类别

    如下定义的r类型为int&&, 但r在做为表达式时的值类别是左值,所以推动出的类型是int&

    int&& r = 2;
    __cs(__typeofObj(r));   // r=int&&
    __cs(__typeofExpr(r));  // r=int&

可以在c++11及以上版本中使用.

c++工具函数 - 如何得到类型字符串

__FUNCPRT__

使用宏__FUNCSIG__ (vc++)或者__PRETTY_FUNCTION__ (gcc, clang)来实现这个功能.

#if defined(_MSC_VER)
#define __FUNCPRT__ __FUNCSIG__
#else
#define __FUNCPRT__ __PRETTY_FUNCTION__
#endif

为兼容编译器, 如上处理得到__FUNCPRT__.

decltype(obj) 或 decltype((obj))

template <class T>
const char* typeInfoGet() {
    return __FUNCPRT__;
}

然后为了获取对象的类型字符串, 需要通过上面的typeInfoGet模板, 即typeInfoGet<decltype(obj)typeInfoGet<decltype((obj))>:

  • decltype(obj)获取求解对象定义时的类型
  • decltype((obj))获取求解对象做为表达式时的类型

对于A fn21(A a)函数, 通过typeInfoGet<decltype(fn21)获取到的__FUNCPRT__的字符串内容是: const char* typeInfoGet() [with T = A(A)], 对于const char* typeInfoGet() [with T = 36个字符以及后面的]字符,是不需要的, 即s.substr(36, s.size() - 37)只需要A(A)字符串.

__typeofObj(obj)__typeofExpr(obj)

最后通过自定义的宏: __typeofObj(obj)__typeofExpr(obj), 这两个宏是为了简化获取类型字符串的手写代码量, 利用宏参数字符串即#obj, 结合typeStr函数完成类型字符串获取.

#include <iostream>
using namespace std;

#if defined(_MSC_VER)
#define __FUNCPRT__ __FUNCSIG__
#else
#define __FUNCPRT__ __PRETTY_FUNCTION__
#endif

template <class T>
const char* typeInfoGet() {
    return __FUNCPRT__;
}

std::string typeStr(const char* cstr, const char* name) {
    std::string s(cstr);
    std::string n(name);
    return n.append("=").append(s.substr(36, s.size() - 37));
}

#define __typeofObj(obj) typeStr(typeInfoGet<decltype(obj)>(), #obj);
#define __typeofExpr(obj) typeStr(typeInfoGet<decltype((obj))>(), #obj);

#define __cs(expr) cout << "\n" << expr;

struct A {
    A() { cout << " 默认构造;"; }
};
A fn21(A a) { return a; }

int main() {
    __cs(__typeofObj(fn21));  // fn21=A(A)

    int a = 2;
    __cs(__typeofObj(a));   // a=int
    __cs(__typeofExpr(a));  // a=int&
    __cs(__typeofExpr(std::move(a)));  // std::move(a)=int&&

    int&& r = 2;
    __cs(__typeofObj(r));   // r=int&&
    __cs(__typeofExpr(r));  // r=int&

    return 0;
}

以上完整代码在线 cpp 调试链接