因为数组形参会退化为指针,sizeof返回指针大小而非数组字节数;别名模板通过引用类型T(&)[N]保留维度信息,使sizeof(arr)正确返回40,并支持编译期尺寸推导与约束。

为什么 void func(int arr[10]) 里 sizeof(arr) 不是 40?
因为 C++ 中数组形参会自动退化为指针,int arr[10] 实际等价于 int* arr,编译器根本不知道原始长度。所以 sizeof(arr) 返回的是指针大小(通常是 8),不是数组总字节数。
别名模板不是“修复”退化,而是绕过它——让你在函数签名里显式保留维度信息,迫使调用方传入带大小的类型。
- 直接写
int arr[10]是假性语法糖,毫无约束力 - 用
std::array<int></int>可行,但要求调用方也改用std::array,不兼容原生数组 - 别名模板的核心价值:接受原生数组(如
int a[10]),同时在函数内拿到尺寸
怎么用 using 别名模板保留维度?
关键不是模板本身,而是让函数模板参数推导出数组类型(含大小),再用 using 给它起个带尺寸的别名。例如:
template<typename T, size_t N>
using array_ref = T(&)[N]; // 引用别名,绑定原生数组
<p>void process(array_ref<int, 10> arr) {
static_assert(sizeof(arr) == 40, "arr must be int[10]");
// 这里 arr 是 int(&)[10],sizeof 正确返回 40
}注意:array_ref<int></int> 是引用类型,只能绑定左值数组(如局部数组、全局数组),不能绑定指针或临时数组。
立即学习“C++免费学习笔记(深入)”;
- 调用必须是
int data[10] = {}; process(data);—— 编译器能推导出data是int[10] - 如果写
process(&data[0])会编译失败:无法将int*绑定到int(&)[10] - 别名中
T(&)[N]的括号不能省,T&[N]是非法语法
如何泛化成任意长度?用模板参数推导 + 别名
硬编码 10 没意义。真正实用的是让编译器自动推导 N,再通过别名把类型“具名化”供内部使用:
template<typename T, size_t N>
void process_impl(T (&arr)[N]) {
using arr_type = T[N]; // 原生数组类型
using arr_ref = T(&)[N]; // 引用类型(常用)
constexpr size_t len = N; // 尺寸可用作 constexpr
<pre class="brush:php;toolbar:false;">// 现在可以安全做 sizeof(arr), std::extent_v<decltype(arr)> 等}
// 调用方无需指定 N,由实参推导 int a[7]; process_impl(a); // T=int, N=7 自动确定
这里 using 不是必须的,但它让后续代码更清晰——比如你想写一个辅助函数只接受和 arr 同尺寸的另一数组,就可以用 arr_ref 作为参数类型。
- 不要试图在非模板函数里“恢复”维度:C++ 标准禁止运行时从指针反查数组长度
- 若需动态长度,该用
std::span<t></t>(C++20)或手动传len参数 - 别名模板(
template<class t size_t n> using X = ...</class>)适合封装复杂类型,但推导仍依赖函数模板参数
容易被忽略的坑:引用绑定、cv 限定符、多维数组
别名模板看着简洁,但实际用错一两个符号就编译失败,而且错误信息往往晦涩。
-
T(&)[N]是左值引用,无法绑定右值数组(如process_impl({1,2,3}));要支持需额外加const T(&&)[N]重载 - 原数组带
const(如const int x[5]),别名必须写成const T(&)[N],否则类型不匹配 - 二维数组如
int mat[3][4],其类型是int[3][4],不是int**;对应别名应为T(&)[M][N],且模板需两个非类型参数 - Clang 和 GCC 对数组引用别名的诊断提示差异大,建议用
static_assert(std::is_array_v<decltype>)</decltype>快速验证是否真拿到了数组类型
最常被跳过的一步:确认你真的需要编译期尺寸。如果只是遍历,传 begin/end 迭代器或 std::span 更灵活;只有当你必须做 sizeof、std::array 转换或 SFINAE 分支时,才值得引入这套别名机制。


















