
typeid 返回的是运行时类型信息,不是类型本身
很多人以为 typeid 能直接拿来当类型用,比如写 typeid(int) 就想得到 int 类型——不行。typeid 返回的是 std::type_info 对象,只能用来比较、打印名字或做运行时识别,不能参与编译期类型推导或模板实例化。
常见错误现象:std::vector<typeid> v;</typeid> 编译失败;auto t = typeid(x); decltype(t) y; 得到的不是 x 的类型,而是 std::type_info const&。
- 要用类型名(如
int、std::string)时,别碰typeid,它不返回类型 -
typeid(x).name()输出的是编译器特定的 mangled 名,可读性差,调试时建议配合abi::__cxa_demangle(GCC/Clang)或__unDName(MSVC) - 开启 RTTI 是前提:禁用
-fno-rtti会导致typeid不可用,链接时报错undefined reference to `typeinfo for ...`
decltype 用于提取表达式的类型,但括号和语义很关键
decltype 是编译期工具,核心规则就一条:看表达式“怎么写的”,而不是“求出来是什么”。括号包不包,加不加引用,结果可能天差地别。
使用场景:写模板时需要保持参数原始类型(比如转发引用)、定义与某变量同类型的别名、避免手动写冗长类型名。
立即学习“C++免费学习笔记(深入)”;
-
decltype(x)→ 如果x是变量名,结果是x的声明类型(含 const/volatile 引用) -
decltype((x))→ 多了一对括号,x变成左值表达式,结果总是T&(T 是x的类型) -
decltype(func())→ 按函数返回类型推导;若返回int&&,decltype就是int&&,不是int - 注意和
auto区别:auto x = expr;会忽略引用和顶层 const,decltype则原样保留
示例:
int i = 42;<br>const int& cr = i;<br>decltype(i) a; // int<br>decltype(cr) b; // const int&<br>decltype((i)) c; // int&<br>decltype((cr)) d; // const int&
什么时候该用 typeid,什么时候该用 decltype
两者根本不在一个维度:一个是运行时反射机制,一个是编译期类型查询。混用或互换基本等于走错楼层。
典型误用:if (typeid(x) == typeid(y)) { auto z = decltype(x){}; } ——语法错误,decltype 不是函数,不能 runtime 调用。
- 需要在运行时判断对象实际类型(比如多态基类指针指向谁)→ 用
typeid,且确保开启 RTTI、对象有虚函数 - 要在编译期获得某个表达式“本来的类型”,用于别名、模板参数、变量声明 → 用
decltype - 想获取模板参数的“去除引用/const 后的裸类型”?别硬套
typeid或decltype,改用std::remove_reference_t+std::remove_cv_t - 性能影响:
typeid有轻微运行时开销(查虚表、字符串比较),decltype零成本,纯编译期行为
容易被忽略的兼容性细节
不同标准版本和编译器对 typeid 和 decltype 的支持边界其实有差异,尤其在模板和 lambda 中。
- C++11 起
decltype支持“带尾置返回类型”的函数声明,但早期 GCC(4.7 前)对decltype(auto)支持不全 -
typeid在未定义行为下(如对空指针调用)是未指定行为,不是崩溃——可能静默返回基类type_info,也可能 abort - lambda 表达式类型:每个 lambda 都有唯一匿名类型,
typeid([]{}) != typeid([]{})恒成立;但decltype([]{})可用于模板参数,只要类型一致就能匹配 - 结构化绑定 +
decltype:C++17 起decltype(auto [a, b] = t)不合法,必须先解构再对各变量分别decltype
事情说清了就结束。










