【C++】定义返回数组指针的函数
我们知道,不能直接将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值,因此,函数无法直接返回一个数组,不过,函数可以返回一个数组的指针或者引用。
【注】一些编译器支持数组的赋值,但最好避免使用非标准特性,以防止程序在其他编译器上无法正常工作。
这里给出四种方式,用于定义一个返回数组指针的函数,其中第三和第四种方式需要支持 C++11。
一. 朴素定义
朴素定义是我自己起的一个名字。。。就是指一个毫无技巧、粗暴地结合函数的定义和数组的定义的定义形式:
// 函数定义
ReturnT Func(parms) {
// function body
}
// 数组定义
ElemT arr[dim];
// 返回数组指针
ElemT (*Func(parms))[dim] {
// function body
}
这个定义看起来略微复杂且毫无美感,如果觉得上面的定义十分混乱难以理解,可以试着按照以下的步骤来阅读这个糟糕的定义:
- Func(parms) 定义了一个函数;
- (*Func(parms)) 表示可以对函数的结果进行解引用,请不要忘记最外面这一层括号,这是必须要有的!如果没有这对括号,函数的返回类型将是指针的数组!
- (*Func(parms))[dim] 表示对函数的结果进行解引用,将会得到一个数组;
- ElemT (*Func(parms))[dim] 表示数组中元素的类型是 ElemT。
上面的步骤看起来有点繁琐,也显得不够简洁。幸运的是,C++ 支持使用类型别名来简化上面的定义。
二. 使用类型别名
正如上面所说的,想要直接定义一个返回数组的指针或引用的函数相当繁琐,而使用类型别名恰好可以简化可以简化这一任务。类型别名可以视为某一类型的同义词,它可以让复杂的名字变得简单明了和易于使用。
typedef T ArrT[dim];
using ArrT T[dim]; // c++11
// func 返回一个指向含有 dim 个元素的数组的指针
// 数组中元素的类型为 T
ArrT *Func(parms) {
// function body
}
从上面的定义中可以看到,使用类型别名确实可以让代码看起来干净简洁易于理解和使用。
三. 使用 auto 和尾置返回类型
C++11 引入了 auto 类型说明符,可以让编译器通过初始值来推算变量的类型。C++11 也支持尾置返回类型,用法是在形参列表后面用一个 “->” 后跟随一个类型,以此表示函数真正的返回类型跟在形参列表之后,而在前面本该放置函数返回类型的的地方放置一个 auto。
auto Func(parms) -> ReturnT {
// function body
}
任何函数的定义都可以使用尾置返回类型,但是这种定义形式对于复杂返回类型最为有效。(内在基础类型和类类型也可以用,但是一般情况下没必要且意义不大)
使用 auto 和尾置返回类型来定义返回数组指针的函数是另一个不错的思路:
// 也请不要忘记这里的括号,这很重要!!
auto Func(parts) -> T(*)[dim] {
// function body
}
四. 使用 decltype
C++11 引用了第二种类型说明符 decltype,用于选择并返回操作数的数据类型。
T tval;
decltype(tval) val; // val 的数据类型是 T
因此,我们可以使用 decltype 来声明返回数组指针的函数,只要我们已经有了一个指向数组的指针对象。
T arr[dim];
decltype(arr) *Func(parms) {
// function body
}
需要注意的是,decltype 并不会把数组转换成对应的指针,因此 decltype 的结果是个数组,即 T[arr],但是我们需要的是一个指向数组的指针,因此在函数声明时要加一个 * 符号。