You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++数组按引用传递的实现方式及相关语法问题详解

#include <iostream>

template <class T>
void call_1(T& in){
  printf("%d\n", sizeof(in));  // 12
}

template <int N>
void call_2(int (&in)[N]){
   printf("%d\n", sizeof(in)); // 12
}

int main(){
  int a[] = {1,2,3};
  call_1(a);
  call_2(a); 
  return 0;
}

问题1:call_1和call_2是否均为将整个数组按引用传递的合法实现方式?

是,二者均是合法的数组按引用传递实现:

  • call_2是显式固定数组元素类型为int的版本,模板参数N会根据传入的数组长度自动推导,形参int (&in)[N]就是长度为N的int数组的引用,不会触发数组退化。
  • call_1是通用版本,模板推导时会直接匹配数组的完整类型,此处传入int[3]类型的数组a时,T会被推导为int[3],形参最终类型为int (&in)[3],和call_2的形参类型完全一致,同样不会触发数组退化。
    二者运行时输出的sizeof(in)均为整个数组的大小12(3个4字节int),也验证了确实是按整个数组引用传递,而非传递指针。

问题2:call_1的参数声明中为何必须使用T&?如果省略&会传递数组首元素的指针,为何T&不会推导为数组首元素的引用,而是匹配整个数组的引用?

  • 省略&后,形参会变成值传递,C++中数组做值传递参数时会触发数组到指针的退化,数组名会被转换为首元素的指针,形参最终为T*类型,此时sizeof(in)得到的是指针的大小(32位环境下4、64位环境下8),无法拿到整个数组的大小。
  • 当形参为左值引用类型T&时,模板参数推导规则明确规定不会触发数组退化,会优先匹配实参的完整原始类型。此处实参a的原始类型就是int[3],没有经过任何类型转换,因此T会直接推导为int[3],形参就是整个数组的引用,不会退化为指针,也不会推导为单个元素的引用——因为单个int的引用和int[3]类型的实参类型不匹配,模板推导不会主动做这种类型截断。

问题3:call_2的模板声明中为何不能写template <T N>来避免硬编码int类型?该写法是否属于合法C++语法?

这个写法在当前上下文是非法的,原因是模板参数列表中使用的T没有被声明过,编译器无法识别T是什么类型。
如果要实现支持任意元素类型的通用数组引用传递,不需要硬编码int的正确写法是声明两个模板参数:

template <class T, size_t N>
void call_2(T (&in)[N]){
   printf("%d\n", sizeof(in));
}

其中T代表数组元素的类型,N代表数组长度,二者都可以通过传入的数组自动推导,不需要显式指定。
C++20之后新增了auto非类型模板参数语法,允许写template <auto N>,但该写法也不适合当前场景,因为你需要同时推导数组的元素类型和长度,还是需要单独声明元素类型参数T。

内容的提问来源于stack exchange,提问作者Dan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 12:21:04