typeid仅对多态类型可靠,非多态类(如无虚函数的Struct A)上不保证返回正确动态类型;std::is_same用于编译期类型比较,二者不可混用。

运行时无法直接“判断变量类型”——typeid 和 std::is_same 解决的是不同层面的问题,混用会出错。
typeid 只能在运行时获取类型信息,且仅对多态类型可靠
typeid 返回 std::type_info 对象,但它在非多态类(即不含虚函数的类)上不保证返回有意义的动态类型。例如:
struct A { int x; }; struct B : A { virtual ~B() = default; }; // 加了虚析构才有多态性 A a; B b; std::cout << typeid(a).name() << "n"; // 可能输出 "1A",但不反映实际派生关系 std::cout << typeid(&b).name() << "n"; // 输出可能为 "P1B"(指针),不是你想要的类型名 std::cout << typeid(*static_cast(&b)).name() << "n"; // 仍是 "1A" —— 非多态,无法识别 B
- 只有指向多态类型的指针或引用,
typeid才能正确返回**实际对象类型** -
typeid的.name()是编译器相关字符串,不可直接比较;应使用==比较std::type_info对象本身 - 不能用于模板参数推导、
if constexpr等编译期场景
std::is_same 是编译期元函数,只能用于已知类型名的静态比较
std::is_same(c++17 起可用 std::is_same_v)只在编译期起作用,它不接受变量,只接受类型:
int x = 42; // ❌ 错误:不能把变量传给 is_same // static_assert(std::is_same_v); // 这行合法 // static_assert(std::is_same_v); // 合法,但依赖另一个表达式 template void check_int() { static_assert(std::is_same_v, "T must be int"); }
- 常见误用:试图用
std::is_same判断运行时值的类型——它根本看不到运行时数据 - 它常用于 SFINAE、
if constexpr、概念约束等编译期分发逻辑 - 注意
const/&/&&会影响结果:std::is_same_v是false
想实现类似“反射”的类型分支?优先用 if constexpr + 类型特征
真正实用的类型分发,几乎都不靠 typeid,而是结合 decltype 和编译期类型判断:
立即学习“C++免费学习笔记(深入)”;
template void handle(T&& val) { if constexpr (std::is_integral_v>) { std::cout << "integral: " << val << "n"; } else if constexpr (std::is_floating_point_v>) { std::cout << "float: " << val << "n"; } else if constexpr (std::is_same_v, std::string>) { std::cout << "string: " << val << "n"; } }
-
std::decay_t去除引用/const/volatile,避免匹配失败 -
if constexpr在编译期丢弃不满足条件的分支,无运行时开销 - 不要试图在运行时“检测未知变量类型并执行不同逻辑”——C++ 不支持这种动态反射;若真有此需求,需手动建模(如 variant + visit)或引入第三方库(如 RTTR)
真正难的不是写对 typeid 或 std::is_same,而是分清:你要解决的问题到底发生在编译期还是运行时。前者靠模板和类型特征,后者若涉及多态对象,才轮到 typeid 出场——而且它也只告诉你“是什么”,不帮你自动调用对应逻辑。