std::size是最直接安全的方式:C++17起为编译期constexpr函数,支持原生数组和容器,返回std::size_t;对指针重载被删除,避免sizeof(arr)/sizeof(arr[0])的静默失效。

用 std::size 是最直接安全的方式
从 C++17 开始,std::size 是标准库提供的编译期常量表达式函数,适用于所有原生数组和容器,返回类型为 std::size_t,且在 constexpr 上下文中可求值。
- 对原生数组(如
int arr[5]),std::size(arr)展开为字面量5,不产生运行时开销 - 支持多维数组:
int m[3][4]→std::size(m)得3,std::size(m[0])得4 - 比手写
sizeof(arr)/sizeof(arr[0])更安全:后者在传入指针时静默失效,而std::size对指针重载被删除,编译报错
模板推导 + sizeof 仍有效但需谨慎
在不支持 C++17 的环境(如某些嵌入式工具链),或需完全控制推导逻辑时,可借助函数模板捕获数组类型:
template<typename T, std::size_t N>
constexpr std::size_t array_size(T (&)[N]) { return N; }
- 必须传入数组名(非指针),否则无法匹配引用形参,编译失败
- 不能用于
extern声明的数组(类型信息不完整) - 若数组是类成员或结构体内嵌,需确保访问路径不触发 ODR-use,否则可能链接失败
std::extent_v 适合元编程场景
当需要在类型层面提取维度(比如写 trait 或 SFINAE 检查),std::extent_v<t i></t> 提供编译期整型常量:
-
std::extent_v<int></int>→3,std::extent_v<int></int>→4 - 对非数组类型(如
std::vector<int></int>)返回0,可用于特化分支判断 - 注意:仅对「数组类型」有效;
int*、std::array<int></int>均不适用(后者要用std::tuple_size_v)
常见陷阱:传参后数组退化成指针
这是最易踩的坑——只要数组作为函数参数传递(未用引用或模板),就失去大小信息:
立即学习“C++免费学习笔记(深入)”;
void f(int a[]) { std::cout << std::size(a); } // ❌ 编译错误:a 是 int*,无 std::size 重载
void g(int (&a)[10]) { std::cout << std::size(a); } // ✅ 正确:引用绑定,大小保留
- 函数形参写
int a[N]和int a[]完全等价,都是指针,N 被忽略 - lambda 捕获数组变量时同样退化,需显式按引用捕获:
[&arr]{ std::size(arr); } - 宏定义中用
sizeof计算大小时,务必确保传入的是数组名本身,而非经过中间变量或函数返回值
std::size;需要泛型推导时上模板;做类型特征判断才动 std::extent_v。三者混用容易因退化时机错乱导致编译失败或结果不符预期。


















