std::is_array配合static_assert可校验模板参数是否为原生数组,需用std::remove_reference_t去除引用;它不识别std::array,若需支持两者须手动组合判断;T(&&)[N]形参可天然排除指针和容器但不支持右值及多维数组;C++20概念更清晰但仍需处理cv/ref修饰。

用 std::is_array + static_assert 检查数组类型
模板参数无法直接写成「必须是数组」,但可以在实例化时主动校验。最直接的方式是在函数或类模板内部用 std::is_array 判断,并配合 static_assert 报错:
template <typename T>
void process_array(T&& arr) {
static_assert(std::is_array_v<std::remove_reference_t<T>>,
"T must be an array type");
// ... 实际逻辑
}
注意要先用 std::remove_reference_t 去掉引用,否则 int([5]) 这类引用类型会误判为非数组。
区分原生数组和 std::array
std::is_array 只识别 C 风格原生数组(如 int[3]、char[10]),对 std::array<int, 3> 返回 false。如果想同时支持两者,得手动组合判断:
- 用
std::is_array_v<T>检原生数组 - 用
std::is_same_v<T, std::array<...>>或更泛化的std::is_specialization_of_v<T, std::array>(需自定义 trait)检std::array - 常见错误:把
std::vector当作数组传入——它既不是原生数组也不是std::array,static_assert会直接触发失败
用模板参数推导限制维度和元素类型
如果还需约束数组的元素类型或维度,可以显式写出数组形式的模板参数:
立即学习“C++免费学习笔记(深入)”;
template <typename T, std::size_t N>
void handle_fixed_array(T (&arr)[N]) {
static_assert(std::is_same_v<T, int>, "only int arrays allowed");
// arr 是 int[5]、int[10] 等的左值引用,N 自动推导
}
这种方式天然排除指针、std::vector、std::array ——它们无法匹配 T(&)[N] 形参。但缺点是不支持右值数组(如临时 {1,2,3}),也不能处理多维数组(int[2][3] 的 T 会是 int[3],需额外偏特化)。
为什么不用概念(C++20)?
C++20 概念写起来更清晰,但要注意实际约束粒度:
template <typename T> concept IsRawArray = std::is_array_v<std::remove_cvref_t<T>>;
这个概念仍需搭配 std::remove_cvref_t,否则 const int[5] 或 int([5])&& 会失败。而且概念只作用于模板参数声明处,不改变底层匹配规则——比如你仍不能靠概念让 std::vector 通过检查,它根本不会进入该重载分支。
真正容易被忽略的是数组退化行为:传入函数的原生数组参数若写成 T* 或 std::span<T>,类型信息就彻底丢失了,后续所有静态检查都失效。所以限制必须落在「模板参数本身能保留数组维度和 cv 属性」的位置上,而不是在运行时或中间转换后。


















