std::is_pointer和std::is_reference各自独立判断指针与引用类型,不互斥也不覆盖所有非基础类型;前者仅识别t*及其cv变体,后者仅识别直接的&或&&,二者均不穿透类型,合用时不能替代remove_pointer_t/remove_reference_t进行类型剥离。

std::is_pointer 和 std::is_reference 不是互斥判断,而是各自独立检查不同语义;一个类型可以同时不是指针、也不是引用,也可以既是(不可能)——但常见误判恰恰出在“以为它们覆盖了所有非基础类型”。
std::is_pointer 只认 T* 及其 cv 修饰变体
它不识别成员指针(如 int A::*)、不识别 std::nullptr_t、也不把引用当指针。哪怕你写 const int*&,std::is_pointer_v<const int></const> 仍是 false,因为顶层是引用,不是指针。
- 返回
true的典型:int*、void*、char* const volatile、int (*)()(函数指针) - 返回
false的典型:int&、int&&、int[10]、int A::*、std::nullptr_t、decltype(nullptr) - 注意 cv 限定只作用于指针本身,不影响判定:
int* const和int*都返回true
std::is_reference 只认 & 和 &&,且不穿透
它检测的是类型是否**直接**为左值或右值引用,不会自动剥离引用再查底层。所以 std::is_reference_v<int></int> 是 true,但 std::is_reference_v<int></int> 是 false(这是个语法错误),而 std::is_reference_v<decltype></decltype> 是否为 true 取决于 ptr 类型——如果 ptr 是 int*,*ptr 是 int&,那结果就是 true。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
std::is_lvalue_reference_v<t></t>和std::is_rvalue_reference_v<t></t>更精确,可分开用 -
std::is_reference_v<int></int>返回true,但std::is_lvalue_reference_v<int></int>是false - 对
auto&& x = expr;这类万能引用,std::is_reference_v<decltype></decltype>总是true,但具体是左还是右,得看expr的值类别
二者合用时常见逻辑陷阱
很多人想“排除指针和引用后得到‘裸’类型”,直接写 !std::is_pointer_v<t> && !std::is_reference_v<t></t></t> ——这会漏掉数组、函数类型、类类型等合法非指针非引用类型;更危险的是,它不能替代 std::remove_pointer_t 或 std::remove_reference_t 做类型转换。
- 正确剥离指针:用
std::remove_pointer_t<t></t>,而不是靠is_pointer判断后手动写T::element_type - 正确剥离引用:优先用
std::remove_reference_t<t></t>,它对T&、T&&、T都安全,而is_reference只是告诉你“要不要剥” - 若需判断“是否为原始数据载体”,应组合多个 trait:
std::is_arithmetic_v<t> || std::is_enum_v<t> || std::is_class_v<t></t></t></t>,而非仅靠 pointer/reference
最易被忽略的一点:这些 trait 全部在编译期求值,value 成员是 constexpr,但如果你在模板中依赖它们做分支,记得配合 if constexpr(C++17 起)或 SFINAE 手段,否则普通 if 会导致未实例化代码仍被检查而报错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










