std::is_pointer 可在编译期判断模板参数是否为指针类型,支持T*、cv限定指针等,但不识别智能指针、引用、数组、nullptr_t及用户自定义指针类;需包含<type_traits>,推荐C++17用std::is_pointer_v<T>。

用 std::is_pointer 在编译期判断模板参数是否为指针
直接用 std::is_pointer 配合 static_assert 或 SFINAE 就能完成编译期检查,不需要手写类型特征。它在 <type_traits> 中定义,对所有标准指针(包括 T*、T const*、成员指针等)返回 true,对引用、数组、函数类型等返回 false。
常见错误是传入 T& 或 T[] 后误以为是指针——std::is_pointer<int&>::value 是 false,std::is_pointer<int[]>::value 也是 false,这点很明确。
- 必须包含头文件:
#include <type_traits> -
std::is_pointer是变量模板(C++17 起),推荐写法:std::is_pointer_v<T>;C++11/14 用std::is_pointer<T>::value - 它不识别智能指针(
std::unique_ptr、std::shared_ptr),这些是类类型,std::is_pointer_v<std::unique_ptr<int>>为false
在模板函数中强制要求指针类型
最常用场景是约束函数模板只接受指针,否则编译失败。用 static_assert 最直观,报错信息也清晰。
template <typename T>
void process_ptr(T ptr) {
static_assert(std::is_pointer_v<T>, "T must be a pointer type");
// ... 实际逻辑
}
调用 process_ptr(new int(42)) 没问题;但 process_ptr(42) 或 process_ptr(std::string{}) 会触发编译错误,消息就是上面字符串。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 注意:
T是推导出的完整类型,比如传入int*,则T == int*,std::is_pointer_v<T>为true - 如果希望支持
const int*、volatile char*等带 cv 限定的指针,std::is_pointer默认支持,无需额外处理 - 不要写成
static_assert(std::is_pointer_v<decltype(ptr)>)——T已经是类型,重复推导没必要
用 std::enable_if 实现重载或特化
当需要为指针和非指针提供不同实现时,SFINAE 更合适。比如写两个同名函数模板,一个只对指针启用,另一个处理其他类型。
template <typename T>
auto deref(T t) -> std::enable_if_t<std::is_pointer_v<T>, decltype(*t)> {
return *t;
}
template <typename T>
auto deref(T t) -> std::enable_if_t<!std::is_pointer_v<T>, T> {
return t;
}
这样 deref(int_ptr) 调用第一个版本,deref(42) 调用第二个。C++20 后可用 requires 替代,更简洁:
template <typename T>
auto deref(T t) requires std::is_pointer_v<T> {
return *t;
}
template <typename T>
auto deref(T t) requires (!std::is_pointer_v<T>) {
return t;
}
- SFINAE 方式在 C++11–17 中可靠,但错误信息可能不如
static_assert友好 -
std::enable_if_t必须出现在返回类型或模板参数中,不能放在函数体里 - 若两个重载都匹配(比如
T是void*),编译器仍会按偏序规则选择最特化的那个
容易忽略的边界情况:空指针常量与字面量
nullptr 是类型 std::nullptr_t,不是指针类型,std::is_pointer_v<std::nullptr_t> 是 false。但它是可转换为任意指针类型的空指针常量。
这意味着:如果你写 process_ptr(nullptr),模板参数 T 会被推导为 std::nullptr_t,导致 static_assert 失败——即使语义上它“代表”一个指针。
- 解决办法之一:加一个针对
std::nullptr_t的重载,或在static_assert中放宽条件:std::is_pointer_v<T> || std::is_same_v<T, std::nullptr_t> - 整数字面量如
0或NULL(宏定义为0或((void*)0))在现代 C++ 中已不鼓励用于空指针,且类型推导更不可控,应避免 - 成员指针(如
int (MyClass::*))被std::is_pointer正确识别为false,因为它不是对象指针——这是设计使然,不是 bug
真正难处理的是用户自定义类型重载了指针行为(比如模拟指针的代理类),std::is_pointer 对它们一律返回 false,这时只能靠约定或额外 trait,编译期无法自动识别“行为像指针”的类型。

















