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


















