我一直在学习C++中的数组概念,当我遇到这个问题时:Return an array in c++
有人使用以下声明进行了回答:
int (&f(int (&arr)[3]))[3]
我似乎无法理解关闭括号后面的[3]。我从未见过像这样的函数声明。我理解其余的语法,但我不太明白[3]是如何工作的,因为它位于函数名之后。如果我忽略了一些简单的东西,我提前道歉。我还尝试查看函数声明的规范,但我没有看到任何相关的内容可以链接到下标语法。那么,这怎么可能呢?
我一直在学习C++中的数组概念,当我遇到这个问题时:Return an array in c++
有人使用以下声明进行了回答:
int (&f(int (&arr)[3]))[3]
int arr[3]; //real but weird
int[3] arr; //hypothetical but better and simpler
由于大小为3
是arr
类型的一部分,因此如果所有部分都出现在变量名称的左侧,就更有意义了,就像写下面这样:
unsigned int a;
不要写:
unsigned a int; //analogous to : int a [3];
因此,虽然该语言在使用 unsigned int
时表现得很好,但在使用 int[3]
时表现得非常奇怪。
现在回到函数声明,如果将函数声明为以下形式,那么它将更加优秀:
int[3]& f(int[3]& arr); //hypothetical
只有当所有部分都在变量名的左侧时才可以这样做。但由于它不是这样做的(即该语言要求您在变量名后面的最右侧写入大小),因此您最终会得到这个奇怪的签名:
int (&f(int (&arr)[3])[3]; //real
但您可以通过typedef简化它,如下所示:
typedef int array_type[3];
array_type& f(array_type& arr);
看起来好多了,现在只有 typedef 看起来奇怪。
使用 C++11,你可以编写更好的 typedef:
using array_type = int[3];
array_type& f(array_type& arr);
array_type
视为int[3]
):int[3]& f(int[3]& arr); //hypothetical
嗯,阅读一下C语言创始人Dennis M. Ritchie的文章,了解一下C语言的历史。
看起来我们从B语言到C语言再到C++语言都使用了这种语法...
我认为,声明多个某种“基本类型”的变量的方式是这种奇怪语法的根源:
int a, *b, c[3];
所以,a
只是一个 int
,b
是指向 int
的指针,c
是一个 int
数组...
如果这些 *
和 [3]
是类型定义的一部分而不是变量定义的一部分 - 那么我们需要三行来写出这个类型定义:
int a;
int* b;
int[3] c;
关于如何解析这样的语句,SO C页面上有两个非常好的资源:
cdecl在某种程度上失败了-因为引用不是C的一部分-所以让我们尝试使用顺时针/螺旋规则来解析C声明。
int (&f(int (&arr)[3]))[3]
arr
-> arr &arr
-> arr 是引用 (&arr)
-> arr 是引用 - 周围的 ()
并没有实际改变任何东西(&arr)[3]
-> arr 是指向大小为 3 的数组的引用int (&arr)[3]
-> arr 是指向类型为 int、大小为 3 的数组的引用下面是:
f
-> f f(int (&arr)[3])
-> f 是一个函数,接受 arr 参数,该参数是...&f(int (&arr)[3])
-> f 是一个函数,接受 arr 参数,该参数是...,并返回引用(&f(int (&arr)[3]))[3]
-> f 是一个函数,接受 arr 参数,该参数是...,并返回大小为 3 的数组的引用int (&f(int (&arr)[3]))[3]
-> f 是一个函数,接受类型为 int、大小为 3 的数组的引用作为参数,并返回类型为 int、大小为 3 的数组的引用当然,这段代码应该被替换为对于我来说更容易阅读的版本:
using int3 = int[3];
int3& f(int3& arr);
int (&f (int (&arr)[3]) )[3]
{
return arr;
}
(int (&arr)[3])
部分意味着此函数将一个由3个元素组成的 int 数组的引用作为参数。这也是将被返回的相同的 arr
。f
是函数的名称。 int &f()
表示您返回对 int
的引用,但您需要返回固定大小的数组,因此应添加 [3]
。括号包围 &f(...)
是因为在 c++ 中,您在变量名之后而不是类型名之后编写数组的大小,就像 Nawaz 在他的回答中所解释的那样。如果省略这些括号,编译器将解释 f
为引用数组,例如 int & f[3]
。