C++ 怎么获取数组长度 C++ sizeof与template推导数组大小【技巧】

8次阅读

用 sizeof 计算数组长度仅在定义作用域内有效,因函数参数会退化为指针;推荐优先使用 std::size,或模板 constexpr Array_size 获取编译期长度。

C++ 怎么获取数组长度 C++ sizeof与template推导数组大小【技巧】

sizeof 计算数组长度时,必须确保传入的是原生数组而非指针

很多人写 sizeof(arr) / sizeof(arr[0]) 却得到错误结果,根本原因是:函数参数一旦声明为 T arr[]T* arr,数组就退化为指针,sizeof 返回的是指针大小(通常是 8),而不是整个数组字节数。

正确做法是只在数组定义作用域内使用该技巧:

  • ✅ 在定义处直接计算:
    int arr[] = {1, 2, 3, 4};
    size_t n = sizeof(arr) / sizeof(arr[0]); // 得到 4
  • ❌ 不要在函数内对形参这么干:
    void foo(int arr[]) {
    size_t n = sizeof(arr) / sizeof(arr[0]); // 错!arr 是 int*,结果恒为 1(64 位下)
    }
  • ⚠️ 字符串字面量要注意结尾 sizeof("abc") 是 4,不是 3

用模板推导数组大小,安全且泛型友好

模板可以捕获数组维度信息,绕过退化问题。核心是让编译器从实参类型中推导出长度 N:

  • 基础写法:
    template
    constexpr size_t array_size(T (&)[N]) {
    return N;
    }

    调用 array_size(arr) 就能拿到 N

  • 更实用的封装c++17 起):
    template
    constexpr size_t size(const T (&)[N]) noexcept {
    return N;
    }

    这和标准库 std::size 行为一致

  • 注意不能用于动态分配内存(如 new int[5])或 std::vector,它们不是数组类型

为什么 std::sizestd::extent_v 都值得了解

std::size 是 C++17 引入的通用容器大小访问接口,对原生数组、std::arraystd::vector 等都有效;而 std::extent_v 是编译期常量,专用于查询多维数组某维度大小:

立即学习C++免费学习笔记(深入)”;

  • std::size(arr) → 运行时可调用,类型安全,推荐日常使用
  • std::extent_v → 得到 3;std::extent_v → 得到 4;仅适用于已知维度的数组类型,不能用于变量
  • 二者不冲突:前者面向值,后者面向类型;std::extent_v 在元编程中更底层、更早可用

容易被忽略的边界情况:多维数组、引用折叠、const/volatile 修饰

模板推导对 cv 限定符和引用很敏感,稍不注意就会匹配失败:

  • 如果数组是 const int arr[5],模板参数需写成 const T (&)[N] 或更稳妥地用 std::remove_cv_t 处理
  • 二维数组传入一维模板会失败:int mat[2][3] 类型是 int[2][3],不是 int[];需显式指定第二维或用嵌套模板
  • 引用折叠可能导致意外:比如 T&& 形参 + 数组左值,会触发引用折叠为 T&,但原始模板仍需匹配 T(&)[N] 才能捕获尺寸
  • 最省心的做法:优先用 std::size;若需编译期常量且确定是原生数组,再上模板 + constexpr

text=ZqhQzanResources