std::is_pointer是编译期零开销类型判断工具,仅对原生指针(t及cv限定变体、void、函数指针)返回true,不识别智能指针、成员指针、引用、数组等;c++17起推荐用_v后缀简化写法,需配合std::decay_t处理引用传参,并注意void*不可解引用。

std::is_pointer 的基本用法和编译期判断逻辑
std::is_pointer 是一个类型特征(type trait),它在编译期返回 true 当且仅当模板参数是一个**裸指针类型**(如 int*、const char*、void*),对其他类型(包括智能指针、引用、数组、函数指针以外的函数类型)都返回 false。它不关心指针指向什么,也不做运行时检查。
常见误用是以为它能识别 std::shared_ptr 或 std::unique_ptr —— 实际上这些是类模板,不是原生指针,std::is_pointer<:shared_ptr>>::value</:shared_ptr> 恒为 false。
- 必须配合
constexpr或模板if constexpr使用才能触发编译期分支 - 直接写
std::is_pointer<t>::value</t>会得到一个bool编译期常量,但不会自动影响代码生成 - 推荐用
std::is_pointer_v<t></t>(C++17 起),更简洁且避免重复写::value
如何在模板中根据是否是指针类型做不同处理
最典型的场景是写泛型函数,想对指针类型解引用,对非指针类型直接取值。这时不能只靠 if,得用 if constexpr:
template<typename t>
auto get_value(T&& t) {
if constexpr (std::is_pointer_v<:decay_t>>) {
return *t; // t 是指针,解引用
} else {
return t; // t 是值或引用,直接返回
}
}</:decay_t></typename>
注意这里用了 std::decay_t<t></t>:因为传入 int*& 时,T 是 int*&,而 std::is_pointer_v<int></int> 是 false(引用不是指针)。衰减后变成 int*,才能正确匹配。
- 没加
std::decay_t是新手最常踩的坑,导致is_pointer在引用传参时永远失效 -
if constexpr分支在编译期被丢弃,所以即使*t对非指针类型语法错误,也不会报错 - 函数指针(如
void(*)())会被std::is_pointer正确识别为true
std::is_pointer 对 cv 限定符和 void* 的兼容性
std::is_pointer 对 const/volatile 修饰的指针完全兼容:const int*、int* const、volatile char* 都返回 true;但 int const* 和 const int* 等价,没问题。
唯一特殊的是 void* —— 它是合法指针类型,std::is_pointer_v<void></void> 为 true,但你不能对 void* 直接解引用(*p 非法)。这意味着仅靠 std::is_pointer 不足以保证 * 合法,还需额外判断是否为 void* 或使用 std::is_object_v<:remove_pointer_t>></:remove_pointer_t>。
-
int**是指针(指向指针),std::is_pointer_v<int></int>也是true -
int[]或int[5]不是指针,返回false;但数组退化成指针(如函数参数void f(int a[])中的a)是另一回事,is_pointer判断的是类型本身,不是形参退化后的类型 -
nullptr_t不是指针类型,std::is_pointer_v<:nullptr_t></:nullptr_t>是false
替代方案:什么时候不该用 std::is_pointer
如果你真正想区分“能不能像指针一样用 -> 或 *”,std::is_pointer 就太窄了 —— 它漏掉所有重载了 operator* 和 operator-> 的类型(比如 std::optional、自定义句柄、迭代器)。这时候应该用 SFINAE 或 C++20 概念检测操作符可调用性,而不是硬编码指针判断。
另一个常见混淆点:有人想用它来判断“变量是否持有有效地址”,这是运行时问题,std::is_pointer 完全无能为力 —— 它只认类型,不看值。
- 检测智能指针应单独判断,例如
std::is_same_v<t std::shared_ptr>></t>或用std::pointer_traits提取元素类型 - 想统一处理“所有可解引用类型”,应优先考虑概念(concept)约束,而非枚举所有指针/智能指针/迭代器类型
- 模板元编程中,
std::is_pointer常作为更复杂 trait 的基础构件,但它自己解决不了语义层面的“指针行为”问题
实际写的时候,最容易忽略的是类型衰减和 void* 的特殊性——前者导致判断失效,后者让解引用逻辑崩掉。这两个点不处理好,std::is_pointer 就只是个半成品判断。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











