在 C++ 中返回数组引用的语法

Syntax for returning an array reference in C++

我一直在复习 C++ 中的数组概念,当我遇到这个问题时:Return an array in c++

有人用这个声明回答:

int (&f(int (&arr)[3]))[3]

我似乎无法理解的是右括号后的 [3]。我从未见过像这样的函数声明。我了解其余的语法,但我不是特别了解 [3] 是如何工作的,因为它在函数名称之后。如果我忽略了一些简单的事情,我会提前道歉。我还尝试查看函数声明的规范,但我没有看到任何与下标语法相关的内容 link 。那么,这怎么可能呢?

该函数返回一个 reference 到一个大小为 3int 的数组,函数后面的 [3] 部分实际上是要作为 reference.

返回的数组的大小

这个晦涩的语法来自数组声明的奇怪语法,你这样做:

int arr[3]; //real but weird

如果有这样的话,语言会简单得多:

int[3] arr; //hypothetical but better and simpler

因为大小3arr类型的部分,所以如果所有的部分都出现在左边更有意义变量名,和你写的一样:

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

希望对您有所帮助。

int (&f (int (&arr)[3]) )[3]
{
    return arr;
}

让我们从里面走吧。 (int (&arr)[3]) 部分表示该函数将对 3 个元素的 int 数组的引用作为参数。这与正在 return 编辑的 arr 相同。

现在,语法的其余部分表示该函数应该 return 对 3 个整数数组的引用。 f 是函数的名称。 int &f() 意味着您 return 对 int 的引用,但您需要 return 固定大小的数组,因此您应该添加 [3]使用 &f(...) 周围的括号是因为在 C++ 中,您将数组的大小写在变量名之后,而不是类型名之后,正如 Nawaz 在他的回答中所解释的那样。如果省略这些括号,编译器会将 f 解释为引用数组,如 int & f[3].

好吧,阅读这篇 article 关于 C 历史的文章,作者 Dennis M. Ritchie。

看起来像我们从 B、C 到 C++ 得到的这种语法...

我相信,这种声明一些 "basic type" 的多个变量的方式是这种奇怪语法的根源:

int a, *b, c[3];

所以 a 只是 intb 是指向 int 的指针,而 cint 的数组...

如果这些 *[3] 是类型定义的一部分而不是变量定义 - 那么我们需要 3 行来编写:

int a;
int* b;
int[3] c;

SO C page 上有两个很好的资源可用于学习如何解析此类结构:

cdecl 有点失败 - 因为引用不是 C 的一部分 - 所以让我们尝试 The Clockwise/Spiral Rule for parsing C declarations.

int (&f(int (&arr)[3]))[3]
  1. arr -> arr
  2. &arr -> arr 是引用
  3. (&arr) -> arr 是参考 - 周围 () 并没有真正改变什么
  4. (&arr)[3] -> arr 是对大小为 3 的数组的引用
  5. int (&arr)[3] -> arr 是对 int
  6. 类型的大小为 3 的数组的引用

下一个:

  1. f -> f
  2. f(int (&arr)[3]) -> f 是接受 arr 的函数,即 ...
  3. &f(int (&arr)[3]) -> f 是接受 arr 的函数,它是 ...,并返回引用
  4. (&f(int (&arr)[3]))[3] -> f 是接受 arr 的函数,它是...,并返回对大小为 3
  5. 的数组的引用
  6. int (&f(int (&arr)[3]))[3] -> f 是接受 arr 的函数,arr 是对 int 类型大小为 3 的数组的引用,并返回对大小为 3 的 int 类型数组的引用

当然 - 至少对我而言,此代码应替换为更易于阅读的版本:

using int3 = int[3];
int3& f(int3& arr);