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

用 std::is_pointer 是最直接的方式
标准库提供了类型 trait,std::is_pointer 就是专为此设计的。它在编译期返回一个 std::integral_constant,所以能用在 static_assert、if constexpr 或模板特化中。
注意:它只对“裸指针”返回 true,不包括智能指针(如 std::shared_ptr)、迭代器或自定义指针类。
-
std::is_pointer→::value true -
std::is_pointer→::value false -
std::is_pointer<:unique_ptr>>::value→false - 别忘了加
#include
在模板中做指针类型分支要用 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></typename>
- 用
std::is_pointer_v(C++17 起)比std::is_pointer更简洁::value - 若在函数模板里判断形参类型,要小心传入的是
T还是T*—— 指针类型本身是T*,不是T - 避免写成
std::is_pointer来判断变量,除非你明确需要其声明类型(比如::value int* const x仍是指针类型)
手动偏特化也能实现,但没必要
有人会尝试写一个自己的 is_pointer 偏特化来理解机制:
template <typename t> struct my_is_pointer : std::false_type {};
template <typename t> struct my_is_pointer<t> : std::true_type {};
</t></typename></typename>
这确实可行,但有明显局限:
- 漏掉
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 是 false。
- 如果业务逻辑里把
nullptr当作“无效指针”统一处理,不能只靠std::is_pointer捕获它 - 需额外检查
std::is_same_v,或用更上层的类型分类(如std::is_null_pointer_v,C++14 起) - 这也是为什么
std::is_pointer和std::is_null_pointer是两个独立 trait
实际用的时候,绝大多数场景直接上 std::is_pointer_v 就行;真要处理 nullptr 或 cv 修饰的指针,得补条件,而不是指望一个 trait 包打天下。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











