std::is_pointer_v是最直接的编译期指针类型判断方式,仅对裸指针返回true,不包括智能指针、迭代器、nullptr_t等,需配合if constexpr使用并包含。

用 std::is_pointer 是最直接的方式
标准库提供了类型 trait,std::is_pointer 就是专为此设计的。它在编译期返回一个 std::integral_constant<bool value></bool>,所以能用在 static_assert、if constexpr 或模板特化中。
注意:它只对“裸指针”返回 true,不包括智能指针(如 std::shared_ptr)、迭代器或自定义指针类。
-
std::is_pointer<int>::value</int>→true -
std::is_pointer<int>::value</int>→false -
std::is_pointer<:unique_ptr>>::value</:unique_ptr>→false - 别忘了加
#include <type_traits></type_traits>
在模板中做指针类型分支要用 if constexpr(C++17 起)
运行时判断没意义——类型信息在编译期就固定了。想根据是否为指针执行不同逻辑,必须用 if constexpr,否则未实例化的分支仍会触发 SFINAE 或编译错误。
template <typename T>
void process(T* ptr) {
if constexpr (std::is_pointer_v<T*>) { // 注意:这里 T* 是指针类型
std::cout << "T* is a pointer\n";
}
}
// 更常见的是判断模板参数本身:std::is_pointer_v<T>
- 用
std::is_pointer_v<t></t>(C++17 起)比std::is_pointer<t>::value</t>更简洁 - 若在函数模板里判断形参类型,要小心传入的是
T还是T*—— 指针类型本身是T*,不是T - 避免写成
std::is_pointer<decltype>::value</decltype>来判断变量,除非你明确需要其声明类型(比如int* const x仍是指针类型)
手动偏特化也能实现,但没必要
有人会尝试写一个自己的 is_pointer 偏特化来理解机制:
立即学习“C++免费学习笔记(深入)”;
template <typename T> struct my_is_pointer : std::false_type {};
template <typename T> struct my_is_pointer<T*> : std::true_type {};
这确实可行,但有明显局限:
- 漏掉
T* const、T* volatile、T* const volatile等 cv 限定变体 - 不处理成员指针(
int (A::*)),而std::is_pointer也不处理——它本来就不负责成员指针(那是std::is_member_pointer的事) - 标准实现还考虑了函数指针、空指针常量(
std::nullptr_t)等边界情况,自己写很难覆盖全
容易忽略的点:nullptr_t 不是指针类型
std::nullptr_t 是独立类型,既不是指针,也不是整型,更不是空类。它的特殊之处在于能隐式转换为任意指针类型,但 std::is_pointer<:nullptr_t>::value</:nullptr_t> 是 false。
- 如果业务逻辑里把
nullptr当作“无效指针”统一处理,不能只靠std::is_pointer捕获它 - 需额外检查
std::is_same_v<t std::nullptr_t></t>,或用更上层的类型分类(如std::is_null_pointer_v<t></t>,C++14 起) - 这也是为什么
std::is_pointer和std::is_null_pointer是两个独立 trait
实际用的时候,绝大多数场景直接上 std::is_pointer_v<t></t> 就行;真要处理 nullptr 或 cv 修饰的指针,得补条件,而不是指望一个 trait 包打天下。


















