用 std::is_integral_v 可在编译期简洁判断整数类型,支持 char、short、long long 和 bool,但不自动识别枚举或自定义类,需注意与 std::is_arithmetic_v 的区别。

怎么判断一个类型是不是整数类型
用 std::is_integral_v 最直接。它在编译期返回 true 或 false,比写 std::is_integral 更简洁,c++17 起推荐用带 _v 后缀的变量模板。
常见误用是拿它去判断自定义类或枚举——默认不成立,除非显式特化。比如:
Static_assert(std::is_integral_v); // ✅ static_assert(!std::is_integral_v); // ✅ static_assert(!std::is_integral_v); // ✅(即使 enum 是 int 底层,也不自动推为 integral)
- 注意
char、short、long long都算std::is_integral_v为true -
bool也算整数类型,这是标准定义,不是 bug - 别和
std::is_arithmetic_v混用:后者还包含Float、double
怎么检测某个类型有没有成员函数
不能靠 std::is_member_function_pointer ——那只是判断“这个东西是不是成员函数指针类型”,不是“某个类有没有某成员”。真要用 SFINAE 或 C++20 的 requires 表达式。
C++20 推荐写法(清晰且可读):
立即学习“C++免费学习笔记(深入)”;
template concept has_foo = requires(T t) { t.foo(); };
如果必须用 C++17 或更早,得靠 std::void_t + 变参模板偏特化,容易写错。典型坑点:
- 忘记把表达式包进 decltype:要写
decltype(std::declval,不能只写().foo()) T::foo - 没处理 const/volatile 限定:
const T调用foo()失败时,整个 trait 会静默失效,建议加const版本单独判断 - 返回类型不匹配也会导致 SFINAE 失效,建议用
int占位,别强求原返回类型
怎么安全地做类型转换(比如 void* → T*)
别手写 reinterpret_cast。先用 std::is_trivially_copyable_v 判断是否能无损二进制复制;再结合 std::is_standard_layout_v 确保内存布局兼容——两者都为 true 才适合用 memcpy 或 std::bit_cast(C++20)。
例如从 raw buffer 构造结构体:
struct Header { uint32_t len; uint16_t flags; }; // 安全前提: static_assert(std::is_trivially_copyable_v); static_assert(std::is_standard_layout_v); // 然后才能: Header h = std::bit_cast(buffer); // C++20 // 或 memcpy(&h, buffer, sizeof(Header)); // C++17
-
std::is_pod_v已弃用(C++20),别再用 - 类含虚函数、非 public 非 static 成员、用户定义构造/析构,基本就不是 trivially copyable
- 哪怕满足条件,也要确保 buffer 长度 ≥
sizeof(T),否则std::bit_cast行为未定义
为什么 std::enable_if_t 在函数模板里总报错
最常见原因是没把它放在函数模板参数列表的“正确位置”:必须作为模板参数的默认值,或作为函数返回类型的一部分,不能当普通函数参数类型写。
正确写法(SFINAE 友好):
template>> T square(T x) { return x * x; }
错误写法(编译失败):
// ❌ 编译器无法推导 T,因为 enable_if_t 不参与推导 template T square(T x, std::enable_if_t>* = nullptr);
- 如果用了多个
std::enable_if_t,建议提取成别名模板,避免重复写长表达式 - C++20 后优先用
requires替代,语义更直白,错误信息也更友好 - 别在类模板参数里滥用
std::enable_if_t:会导致整个类不可实例化,而不是仅禁用某个成员函数
类型萃取本身不难,难的是组合使用时的约束叠加和错误定位。尤其是跨 C++ 标准版本混用 trait(比如在 C++14 项目里硬塞 std::is_aggregate_v)——编译器不会提示“不支持”,而是报一堆无关的模板解析失败。