std::is_array仅在编译期判断类型是否为原生数组(t[n]或t[]),对std::array、指针、引用等均返回false;需配合std::extent_v获取长度,且必须先确认is_array为true。

std::is_array 的基本用法和编译期判断逻辑
std::is_array 是标准库中一个类型特征(type trait),它只在编译期起作用,用于判断某个类型是否为「原生数组类型」(即 T[N] 或不完整数组 T[]),**不是**指 std::array、std::vector 或其他容器。
它的返回值是 std::integral_constant<bool value></bool> 类型,所以实际使用时得取 ::value 或 C++17 起的 ::value_v:
static_assert(std::is_array<int>::value); // true static_assert(std::is_array<int>::value); // true(不完整数组也算) static_assert(!std::is_array<int>::value); // true static_assert(!std::is_array<:array>>::value); // true —— 注意!</:array></int></int></int>
常见误判点:传入指针(如 int*)、引用(如 int(&)[5])或 std::array 都会返回 false,因为它们都不是语言定义的“数组类型”。
为什么 std::is_array 对 std::array 返回 false?
std::array<t n></t> 是一个模板类,本质是带封装的 POD 结构体,内部用 T[N] 成员存储数据,但它自身类型是类类型(class type),不是数组类型。C++ 标准明确规定 std::is_array 只对「cv 限定的 T[N] 或 T[]」返回 true。
如果你需要同时识别原生数组和 std::array,得手动组合判断:
template<typename t>
constexpr bool is_array_like =
std::is_array_v<t> ||
(std::is_class_v<t> && !std::is_same_v<t std::string> && /* 粗略排除常见类 */
std::is_detected_v<:has_data_and_extent t>); // 需自行实现 SFINAE 检测</:has_data_and_extent></t></t></t></typename>
但多数场景下,应明确区分语义:原生数组代表栈上连续内存 + 编译期大小;std::array 是可拷贝、可传递的容器对象。混用 std::is_array 去覆盖两者,反而模糊了类型意图。
在模板中安全使用 std::is_array 的注意事项
直接在函数模板参数上用 std::is_array<t>::value</t> 判断,容易因数组退化(decay)导致误判。例如:
template<typename t>
void foo(T x) {
static_assert(std::is_array_v<t>); // ❌ 即使传入 int[3],T 也会退化为 int*!
}</t></typename>
正确做法是:用引用禁用退化,并配合 std::remove_reference_t 提取原始类型:
- 写成
template<typename t> void foo(T&& x)</typename>并用std::remove_reference_t<decltype></decltype>获取类型 - 或更稳妥地,在形参中显式使用引用:
template<typename t> void foo(T& arr)</typename>,此时T就是int[5]这样的数组类型 - 若需支持右值数组(极少用),注意
T&&对数组类型推导仍为int[5]&&,std::remove_reference_t可正常还原
另外,std::is_array 对 const/volatile 限定不影响结果:const int[3] 和 int[3] 都返回 true。
替代方案:运行时识别数组长度的陷阱
std::is_array 只能告诉你「是不是数组类型」,**不能获取长度**。想拿 N,得靠 std::extent_v<t></t> 配合使用:
static_assert(std::is_array_v<int>); // true static_assert(std::extent_v<int> == 7); // true static_assert(std::extent_v<int> == 0); // 不完整数组返回 0 —— 容易忽略这点</int></int></int>
关键限制:
-
std::extent_v<t></t>对非数组类型返回 0(不是编译错误),所以必须先确认std::is_array_v<t></t>为 true 再用 - 多维数组如
int[2][3],std::extent_v<t></t>只返回第一维(2),要第二维得嵌套用std::extent_v<:remove_extent_t>></:remove_extent_t> - 所有这些操作都要求类型在编译期完全确定,无法用于
auto推导出的指针或运行时数组
真正需要运行时数组信息的场景,应该用 std::span 或显式传入长度,而不是依赖类型特征硬凑。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











