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










