type_traits仅在编译期生效,不能用于运行时类型判断;std::is_integral_v等仅检测类型而非值,适用于模板约束(如static_assert)或sfinae,不可用于if分支分发。

别用 type_traits 做运行时类型判断——它只在编译期生效,写错地方根本编译不过,不是“没效果”而是“压根不走你写的逻辑”。
怎么查一个类型是不是整数(std::is_integral_v)
这是最常踩坑的起点:很多人想用 is_integral 判断变量值是否为整数,比如 if (is_integral_v<decltype>)</decltype> 看起来合理,但实际只能查类型本身,和值无关。比如 double x = 5.0;,decltype(x) 是 double,is_integral_v<double></double> 永远是 false,哪怕 x 此刻存的是整数值。
真正该用的场景是模板约束或 static_assert:
template<typename T>
void process(T val) {
static_assert(std::is_integral_v<T>, "T must be integral");
// ...
}-
std::is_integral_v<t></t>是 C++17 引入的变量模板,比std::is_integral<t>::value</t>更简洁,优先用带_v后缀的 - 注意
char、short、long long都算整数,但bool和enum默认不算(除非显式特化) - 别在 if 分支里依赖它做运行时分发——编译器不会帮你生成两个分支,只会按模板实例化结果走一条路
怎么让函数只接受指针类型(std::is_pointer + enable_if)
想写一个只处理指针的函数?直接加 static_assert 最直白,但若要重载或 SFINAE 友好,得配合 std::enable_if。
立即学习“C++免费学习笔记(深入)”;
常见错误是写成:
template<typename T>
auto foo(T* p) -> void { ... } // 这只是“参数是 T*”,不是“T 是指针”正确做法是让模板参数 T 是任意类型,再用 trait 限制:
template<typename T>
std::enable_if_t<std::is_pointer_v<T>> bar(T ptr) {
// ptr 是 int*, char**, void* 等任意指针类型
}-
std::is_pointer_v<int></int>是true,但std::is_pointer_v<int></int>也是true—— 它判断的是“顶层是否为指针”,不是“是否指向指针” - C++20 起推荐用
requires std::is_pointer_v<t></t>替代enable_if,更易读 - 别漏掉
const和volatile:const int*是指针,int* const也是,std::is_pointer对二者都返回true
为什么 std::is_same_v<t int></t> 在模板里总返回 false?
因为 T 是模板参数,不是具体类型;is_same_v<t int></t> 只有在 T 实际被推导为 时才为 true。你在模板定义里写这个表达式,编译器无法在实例化前判定真假,SFINAE 会把它当失败路径丢弃——除非你用 std::is_same_v<:decay_t>, int></:decay_t> 或其他方式先归一化。
- 典型误用:
if (is_same_v<t int>) { ... }</t>—— 这行代码永远不执行,因为T不是具体类型,条件在编译期无法满足 - 真要用等价判断,得结合
constexpr if(C++17):if constexpr (std::is_same_v<t int>) { ... }</t> -
std::decay_t<t></t>会去掉引用、const/volatile,把int&变成int,适合做“值语义”比较 - 注意
std::is_same_v<int int></int>是false,引用和非引用是不同类型
元编程里最麻烦的从来不是记不住 trait 名字,而是忘了它们只在编译期起作用,且每个 trait 对 cv 限定符、引用、数组维度都敏感。写完一个 static_assert,最好用几个具体类型手动代入验证下,比看文档更快发现问题。










