std::is_array仅识别c风格数组,对指针、std::array均返回false;正确用法是引用传递或模板推导保留数组类型,并仅在if constexpr中编译期判断。

std::is_array 对指针无效,必须传引用或模板推导
直接对变量名用 std::is_array<decltype>::value</decltype> 很容易得到 false,因为数组参数在函数形参里会退化成指针,decltype(x) 拿到的是指针类型而非数组类型。
正确做法是让类型信息不丢失:要么用引用传递,要么靠模板参数自动推导完整类型。
- 函数参数写成
T(&)[N](数组引用)或T[N](但仅限模板中,编译器能推导出 N) - 避免写
void f(int arr[])或void f(int* arr)—— 这两种都丢掉了数组维度和类型信息 - 在非模板上下文中,若只有变量名,可用
std::is_array_v<decltype></decltype>:双括号强制产生左值引用,防止退化(但注意:这只能用于定义处有数组类型的变量,不能用于函数参数)
模板中用 std::is_array_v 判断原始数组,别和 std::array 混
std::is_array 只识别 C 风格数组(如 int[5]、char[10]),对 std::array<int></int> 返回 false。这是常见误解点。
如果你要统一判断“所有带固定长度的数组状类型”,得手动组合判断:
立即学习“C++免费学习笔记(深入)”;
-
std::is_array_v<t></t>→ 原生数组 -
std::is_same_v<t std::array>></t>→ 需特化或用std::is_specialization_of(C++20 起需自行实现) - 别依赖
std::is_trivially_copyable或std::rank来替代——它们不等价
示例:
template<typename T> constexpr bool is_c_style_array_v = std::is_array_v<T>;这样最安全、最明确。
std::is_array 在 constexpr 上下文里能用,但别在运行时分支里硬塞
它是标准库提供的 constexpr 变量模板,可在编译期做类型分发,比如配合 if constexpr 写泛型逻辑。
错误示范是把它当运行时条件用:if (std::is_array_v<decltype>) { ... }</decltype> —— 这不是语法错,但毫无意义,因为类型在编译期就确定了,运行时分支不会生效(编译器可能警告或优化掉)。
- 正确姿势:只在
if constexpr中使用,确保分支被编译器静态裁剪 - 若类型来自模板参数
T,直接写if constexpr (std::is_array_v<t>)</t> - 注意:C++17 要求
if constexpr分支内代码必须语法合法(即使不执行),所以数组分支里别写T::size()这种仅适用于std::array的调用
数组退化发生在函数调用、赋值、模板实参推导之外的多数场景
你以为传个 int arr[3] 进函数还能保留数组类型?除非你显式阻止退化,否则它大概率变成 int*。
真正能保住数组类型的地方其实很有限:
- 模板函数参数写成
template<size_t n> void f(int (&arr)[N])</size_t>→ 引用绑定,N和数组类型全保留 - 变量声明时直接初始化:
auto x = int[3]{1,2,3};不行(语法错),但auto&& x = int[3]{1,2,3};可以(推导为int(&&)[3]) -
decltype遇到变量名默认取声明类型;遇到带括号表达式如(x)取左值引用类型;遇到函数调用取返回类型 —— 所以decltype((x))是关键技巧
最常踩的坑:在函数外用 decltype(x) 看似拿到了数组类型,一进函数体就发现参数已经是 int* 了 —— 类型擦除就发生在那一层调用边界上。










