std::is_pointer_v仅判断裸指针类型,对int返回true,对int&、int[5]、t&&、const int&等返回false;正确用法是先std::decay_t剥离修饰再判断。

它不能判断变量,只能判断类型;传 int* 返回 true,传 int& 或 int[5] 一定返回 false。
std::is_pointer 只能用于类型名,不是变量名
常见错误是写 std::is_pointer_v<decltype></decltype> 却忘了 ptr 是万能引用或带 cv 限定的变量——decltype(ptr) 可能是 T&&、const int*& 或 int* const,这些都不是“裸指针类型”,直接套用会误判。
- 正确做法:先用
std::decay_t<decltype></decltype>剥离引用、cv 限定和数组特性,再喂给std::is_pointer_v - 若明确知道是左值引用(如函数参数
T&),可直接用std::remove_reference_t<t></t> -
std::is_pointer_v<int></int>永远是false,别指望它“识别出引用背后是指针”
偏特化指针类型时,T* 和 T* const 必须分开写
模板偏特化匹配的是类型字面形式,不是语义等价性。比如你只写了 template<typename t> struct X<t></t></typename>,那 X<int const></int> 根本不会命中这个特化——因为 int* const 不是 T* 形式,它是“指针常量”,类型为 int* const。
- 要覆盖所有原生指针,得显式写出:
template<typename t> struct X<t></t></typename>、template<typename t> struct X<t const></t></typename>、template<typename t> struct X<t volatile></t></typename>等 - 更实用的做法是统一用
std::remove_cvref_t预处理类型,再结合std::is_pointer_v做编译期分支 -
std::is_pointer_v<void></void>是true,但void*不能解引用;std::is_pointer_v<:nullptr_t></:nullptr_t>是false,别混淆
if constexpr + std::is_pointer_v 是最简安全用法
C++17 起,if constexpr 让编译期类型分发变得直观且无 SFINAE 风险。但必须确保条件分支里不出现非法表达式,否则即使不执行也会编译失败。
- 错误示范:
if constexpr (std::is_pointer_v<t>) { delete t; }</t>—— 若T不是裸指针,delete t语法错误,编译挂掉 - 正确写法:先用
std::decay_t<t></t>归一化,再判断;删除操作仅在std::is_pointer_v为 true 时展开 - 注意:对智能指针(如
std::unique_ptr<int></int>)std::is_pointer_v返回false,需额外用std::is_same_v或概念区分
最容易被忽略的是 cv 限定符带来的类型分裂——const int* 和 int* const 在模板系统里是完全不同的类型,std::is_pointer_v 虽然对两者都返回 true,但偏特化或重载匹配时不会自动归并。动手前先用 static_assert 打印实际推导出的类型,比猜靠谱得多。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











