std::is_pointer仅对裸指针类型(如int)返回true,不识别智能指针、函数指针(需写成void()())、成员指针、引用或数组;使用时须配合std::decay_t处理引用类型,并优先采用if constexpr而非sfinae。

std::is_pointer 的基本用法和编译期判断逻辑
std::is_pointer 是标准库中一个 type_trait,它在编译期返回 std::true_type 或 std::false_type,仅对「裸指针类型」(如 int*、void*、const char*)返回真值。它不识别智能指针(std::unique_ptr、std::shared_ptr)、函数指针(除非显式写成 void(*)() 形式)、成员指针(int A::*),也不处理引用或数组——这些都会被判定为 false。
关键点在于:它只看类型最外层是否为「T*」语法构造的指针,不递归、不解引用、不推导语义。
-
std::is_pointer_v<int></int>→true -
std::is_pointer_v<int></int>→true(双重指针仍是裸指针) -
std::is_pointer_v<:unique_ptr>></:unique_ptr>→false -
std::is_pointer_v<int></int>→false -
std::is_pointer_v<int></int>→false
如何在模板中安全使用 std::is_pointer_v 做分支选择
直接用 if constexpr 是最常见也最推荐的方式,避免实例化非法代码。比如你想对指针类型做解引用操作,而对非指针类型走另一条路径:
template<typename t>
auto get_value(T&& t) {
if constexpr (std::is_pointer_v<:decay_t>>) {
return *std::forward<t>(t); // 只有 T 是指针时才编译这一行
} else {
return std::forward<t>(t);
}
}</t></t></:decay_t></typename>
注意必须用 std::decay_t<t></t>:否则传入 int*& 这类带引用的类型时,std::is_pointer_v<int></int> 是 false(引用不是指针)。decay 后变成 int* 才能正确识别。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 别漏掉
std::decay_t,尤其模板参数是T&&时 - 避免用
std::enable_if+ SFINAE,现代 C++ 优先选if constexpr - 不能用于非类型上下文(比如作为
static_assert的唯一条件而不加constexpr)
容易误判的边界情况和替代方案
常见误判来自「函数类型」和「成员指针」:void() 是函数类型,void(*)() 才是函数指针;int A::* 是成员指针,但 std::is_pointer_v<int a::></int> 返回 false(它是 std::is_member_pointer_v 的范畴)。
如果你需要覆盖更广的“间接访问”语义(比如统一处理裸指针 + 智能指针),std::is_pointer 就不够用了,得自己定义 trait:
template<typename t>
inline constexpr bool is_dereferenceable_v =
std::is_pointer_v<:decay_t>> ||
std::is_same_v<:decay_t>, std::unique_ptr<auto>> || // 简化示意,实际需 SFINAE 或 concepts
std::is_same_v<:decay_t>, std::shared_ptr<auto>>;</auto></:decay_t></auto></:decay_t></:decay_t></typename>
-
std::is_pointer不等于「能解引用」,只是语法层面的指针标记 - 函数指针要写全
return_type(*)(args),decltype(&func)通常得到的是函数类型,不是指针 - 成员指针、
std::optional<t></t>、std::vector<t></t>等容器内部元素类型,std::is_pointer都无法穿透识别
性能与编译器兼容性注意事项
std::is_pointer_v 是零开销抽象:所有判断都在编译期完成,生成的汇编里不会有任何运行时检查或分支。但它依赖编译器对 type traits 的完整支持——C++17 起已稳定,但某些嵌入式工具链(如旧版 IAR、Keil ARMCC)可能未完全实现 std::is_pointer_v(只提供 std::is_pointer<t>::value</t>),此时需回退。
- Clang/GCC/MSVC 主流版本均无问题,但 CI 中若用
-std=c++14,必须写std::is_pointer<t>::value</t>而非_v后缀 - 不要试图在宏里展开
std::is_pointer_v<t></t>并用于预处理器条件(#if),它不是预编译期常量 - 模板实例化爆炸风险极低,但大量嵌套模板中高频使用该 trait 可能略微拖慢编译速度(可忽略)
真正难的不是怎么写,而是想清楚你到底要识别「语法上的指针」,还是「语义上可间接访问的对象」——前者用 std::is_pointer 刚好,后者就得绕开它重新建模。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










