编译时获取数组大小唯一可靠方式是让编译器看见数组类型本身:用 sizeof(arr)/sizeof(arr[0])(仅限定义作用域内)或函数模板推导(如 template constexpr size_t array_size(t(&)[n]) { return n; }),二者均要求 arr 为真数组而非指针。

编译时确定数组大小靠 sizeof 和模板推导,不是运行时
你不能靠 std::size() 或 .size() —— 那是容器的接口,原生数组没这玩意。编译时知道大小,唯一可靠方式是让编译器“看见”数组类型本身,比如传入函数模板或用 sizeof(arr) / sizeof(arr[0]),但后者必须确保 arr 是真正的数组(非指针)。
sizeof(arr) / sizeof(arr[0]) 为什么有时失效
常见错误:把数组传给函数后,在函数内用 sizeof。此时形参已退化为指针,sizeof(arr) 返回指针大小(通常是 8),结果完全不对。
- ✅ 正确场景:在定义数组的作用域内直接计算,如
int a[5]; size_t n = sizeof(a) / sizeof(a[0]); - ❌ 错误场景:
void f(int arr[]) { sizeof(arr); }—— 这里arr类型是int*,不是数组 - ⚠️ 注意:
sizeof对std::array有效,但返回的是整个对象字节数,不是元素个数;要用std::array::size()或std::size(arr)(C++17 起)
用模板参数自动推导数组长度
这是最安全、最泛用的编译时获取方式,适用于函数参数和 constexpr 上下文。
template<typename t size_t n>
constexpr size_t array_size(T (&)[N]) {
return N;
}</typename>
调用时:int x[12]; auto n = array_size(x); —— n 是 constexpr size_t,可在模板参数、static_assert 中直接用。
- 优势:类型安全,拒绝指针;支持任意元素类型(包括数组嵌套)
- 限制:不能用于动态分配内存(如
new int[10])、不能用于std::vector - 替代写法(C++17):
std::size(arr)内部就是类似模板实现,但底层仍依赖数组类型推导
std::extent_v 在类型元编程中提取维度
当你处理多维数组或需要静态反射(比如模板偏特化),std::extent_v<t n></t> 可以从类型中提取第 N 维长度,且全程编译时完成。
int a[3][4]; static_assert(std::extent_v<decltype> == 3);</decltype>std::extent_v<decltype> == 4</decltype>- 对一维数组:
std::extent_v<int></int>得到7;但对int*或std::array<int></int>返回0(未定义维度) - 注意:
std::extent只看类型,不看变量值;它和sizeof不同,不依赖内存布局
真正难的不是怎么写,而是时刻分清“这个变量到底是不是数组类型”。一旦被隐式转换成指针,所有编译时手段都失效——这时候只能靠约定、封装(如 std::span 带长度)或改用 std::array。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











