函数返回数组指针
因为数组不能被拷贝,所以函数不能返回数组。不过,函数可以返回数组的指针或引用。
虽然从语法上来说,要想定义一个返回数组的指针或引用的函数比较烦琐,但是有一些方法可以简化这一任务,其中最直接的方法是使用类型别名∶
typedef int arrT[10]; // arrT是一个类型别名,它表示的类型是含有10个整型的数组
using arrT = int[10]; // arrT的等价声明
arrT *func(int i); // func返回一个指向含有10个整型的数组的指针
其中 arrT 是含有 10 个整数的数组的别名。
因为我们无法返回数组,所以将返回类型定义成数组的指针。因此,func 函数接受一个int 实参,返回一个指向包含 10个整数的数组的指针。
声明一个返回数组指针的函数
要想在声明func时不使用类型别名,我们必须牢记被定义的名字后面数组的维度:
int arr[10]; // arr是一个含有10个整型的数组
int *p1[10]; // p1是一个含有10个指针的数组
int (*p2)[10] = &arr; // p2是一个指针,它指向含有10个整数的数组
和这些声明一样,如果我们想定义一个返回数组指针的函数,则数组的维度必须跟在函数名字之后。
然而,函数的形参列表也跟在函数名字后面且形参列表应该先于数组的维度。因此,返回数组指针的函数形式如下所示∶
int (*func(int i))[10];
可以按照一下的顺序来逐层理解该声明的含义:
func(int i)
表示调用 func 函数时需要一个 int 类型的实参。(*func(int i))
意味着我们可以对函数调用的结果执行解引用操作。(*func(int i))[10]
表示解引用 func的调用将得到一个大小是10的数组。int (*func(int i))[10]
表示数组中的元素是int类型。
使用尾置返回类型
在C++11 新标准中还有一种可以简化上述 func 声明的方法,就是使用尾置返回类型(trailing return type)。
任何函数的定义都能使用尾置返回,但是这种形式对于返回类型比较复杂的函数最有效,比如返回类型是数组的指针或者数组的引用。尾置返回类型跟在形参列表后面并以一个 -> 符号开头。为了表示函数真正的返回类型跟在形参列表之后,我们在本应该出现返回类型的地方放置一个 auto:
// func接受一个int类型的实参,返回一个指针,该指针指向含有10个整数的数组
auto func(int i) -> int(*)[10];
因为我们把函数的返回类型放在了形参列表之后,所以可以清楚地看到 func 函数返回的是一个指针,并且该指针指向了含有 10 个整数的数组。
使用decltype
还有一种情况,如果我们知道函数返回的指针将指向哪个数组,就可以使用 decltype 关键字声明返回类型。例如,下面的函数返回一个指针,该指针根据参数 i 的不同指向两个已知数组中的某一个:
int odd[] = {1, 3, 5, 7, 9};
int even[] = {0, 2, 4, 6, 8};
// 返回一个指针,该指针指向含有5个整数的数组。
decltype(odd) *arrPtr(int i){
return (i % 2) ? &odd : &even;
}
arrPtr 使用关键字 decltype 表示它的返回类型是个指针,并且该指针所指的对象与 odd 的类型一致。因为 odd 是数组,所以arrPtr返回一个指向含有5个整数的数组的指针。
有一个地方需要注意:decltype并不负责把数组类型转换成对应的指针,所以 decltype 的结果是个数组,要想表示 arrPtr 返回指针还必须在函数声明时加一个*符号。