<p>用偏特化判断指针类型需主模板返回false、偏特化template<typename T> struct is_pointer<T> : std::true_type {}匹配任意T;但const T、T const等cv修饰形式需额外偏特化,否则编译期判断失效。</p>

怎么用偏特化判断类型是否为指针
编译期判断 T* 是最典型的 type traits 场景,核心靠模板主模板 + 偏特化。主模板返回 false_type,偏特化匹配所有指针形式:
template<typename T> struct is_pointer : std::false_type {};
template<typename T> struct is_pointer<T*> : std::true_type {};
注意:必须用 T* 而不是 T const* 或 T volatile* —— 那些需要额外偏特化。C++11 后标准库已覆盖所有 cv 修饰,但自己实现时漏掉 T* const 就会导致 is_pointer<int* const>::value 为 false。
为什么 std::is_same 不能靠全特化暴力匹配
全特化(如 template<> struct is_same<int, int>)看似直接,但无法泛化到任意类型对。真正可行的是用主模板 + 偏特化组合:
template<typename T, typename U> struct is_same : std::false_type {};
template<typename T> struct is_same<T, T> : std::true_type {};
这里关键在 is_same<T, T> 的偏特化:编译器能推导出两个参数为同一类型时才命中。如果写成 template<> struct is_same<int, int>,那它只对 int 有效,完全失去泛型意义。
立即学习“C++免费学习笔记(深入)”;
如何安全萃取数组长度(std::extent 类似逻辑)
数组类型萃取必须区分一维和多维,且不能误伤 std::array 这类模板类。偏特化要严格限定语法:
- 主模板:对非数组类型返回
0 - 偏特化
T[N]:提取N,注意N必须是编译期常量 - 偏特化
T[](不完整数组):返回0,因为长度未知
错误写法:template<typename T, size_t N> struct extent<T[N]> { static constexpr size_t value = N; } —— 这会把 char[5] 和 int[5] 当作不同特化,但实际没问题;真正危险的是忘记处理 const T[N],导致 extent<const int[3]>::value 编译失败。解决方法是把 const、volatile 剥离后再匹配,通常借助 std::remove_cv_t 预处理。
为什么 std::is_class 不能仅靠 sizeof + SFINAE 判断
早期技巧如 sizeof(T()) 在 T 是抽象类或无默认构造函数时会硬报错,而非 SFINAE 沉默失效。标准库实现依赖更底层的编译器内置支持(如 __is_class),但用户模拟时必须用表达式 SFINAE:
template<typename T>
struct is_class {
private:
template<typename U>
static auto test(int) -> decltype(std::declval<U>().~U(), std::true_type{});
template<typename> static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
这个方案仍不完美:对 union 类型也返回 true,且 C++20 后推荐用 std::is_aggregate_v 等更精确的 trait 组合判断。手写 type traits 最容易被忽略的,是 cv 修饰符、引用、数组维度这些“边缘形态”的覆盖完整性 —— 差一个 const T&& 特化,就可能让整个元函数在移动语义场景下失效。


















