c++之数组形参

时间:2022-03-12 13:10:00

1.问题,最近看项目log模块,_log模板函数中的一个参数竟然看蒙x了。函数原形是这样:

template<size_t size>
void _Log(char (&strDest)[size], const char *scetion, const char *key, const char *msg, va_list &parm);

对!就是 char (&strDest)[size]没有看懂。这个传进来的是个字符串数组。

2.翻开c++圣经<c++primer>,找到答案。设计模板类型形参中的 非类型形参和数组引用类型形参。

首先,数组作为形参,有引用和非引用两种形式。一般我们使用非引用形式,也就是将形参定义为数组元素类型的指针,一共有三个等价形式:

  1.void func(int *p);

  2.void func(int p[]);

  3.void func(int p[10]);

其中第三个显示的表明 调用该函数时,所传递的数组最多有10个元素。但是实际上编译器会忽略为任何数组指定的形参长度,换句话说,第三个函数声明中的10,其实是被编译器忽略的。

当我们调用上边的函数时,传递数组名时,数组名会自动转化为指向数组第一个元素的指针。也就是该指针所存放的是数组第一个元素的地址。 然后形参复制的是这个指针指向的地址。

然后,当数组作为形参,采用引用的方式时,形式是这样:

  1.void func(int (&p)[10]);

  当调用此函数时,必须传递的是 具有10个int型元素的数组。类似这样

  int a[10] = {};

  func(a);

  如果这样 int b[2] = {}; func(b); 是不正确的,因为b不是10个元素。当形参是引用类型时,理解引用的含义很重要。引用就是一个变量的别名,但是终究是该变量自己。

  同时,使用引用时,没有复制的环节,大多时候会节省空间,提升效率。

3.但是,我们可以看出,以上形式的数组的引用型形参,是很不方便的。因为传递数组时,存在类型和长度的双重限制。

 那么有没有一种方法,能够解决上述问题呢? 既能用到引用的有点,同时又能避免长度带来的限制?

 答案就是采用 1. 中的模板函数以及使用非类型模板形参。

template<size_t size>

void func(int (&p)[size]){ ... }

圣经中讲到:模板非类型形参是模板定义内部的常量值,在需要常量表达式的时候,可使用非类型形参指定数组的长度, 当调用 func是,编译器会从数组的实参计算非类型形参的值,也就是编译器替我们

计算好了size的值,从而省去我们自己传递长度。这样一来,就可以传递数组元素相同的数组了,不必担心长度。从而避免了2中的缺点

  这样一来:

  int a[10], b[2];

  func(a);func(b)都可以正确调用,同时size的值为a和b的数组长度。

  另外一点需要说明,尽管用了模板的非类型形参,让我们可以省去数组长度的限制,但是实际上,编译器会产生两个func的实例 func<10>, func<2>.

  如果此时声明 int c[10]; func(c); 此时a和c将使用相同的实例。

  这基于: 对于模板的非类型形参而言,求值结果形同的表达式将认为是等价的。

  因此 a和c调用 func(int (&p)[10]), b调用 func(int (&p)[2]).

4.至此,_log函数中的第一个形参已经弄清--数组的应用型形参。同时利用模板的非类型形参,除去了数组长度的限制。

水平有限,欢迎指正错误。