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

8

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

有人使用以下声明进行了回答:

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

我似乎无法理解关闭括号后面的[3]。我从未见过像这样的函数声明。我理解其余的语法,但我不太明白[3]是如何工作的,因为它位于函数名之后。如果我忽略了一些简单的东西,我提前道歉。我还尝试查看函数声明的规范,但我没有看到任何相关的内容可以链接到下标语法。那么,这怎么可能呢?

2
因为K&R是虐待狂。 - orlp
http://cdecl.org/. C语言声明(declarator)语法有时很“有趣”。 - T.C.
1
一旦你明白了,千万不要在真实的代码中写下这样可怕的东西。 - kebs
2
利用C++11的威力:http://cpp.sh/76dc - user2487382
3个回答

8
该函数返回一个大小为3的int数组引用,而函数后面的`[3]`部分实际上是要返回的数组大小的引用。这种晦涩的语法来自于数组声明的奇怪语法,你可以这样声明:
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

希望这可以帮到你。

1
非常感谢!现在所有的东西都变得清晰明了了。 - Izodine

3

嗯,阅读一下C语言创始人Dennis M. Ritchie的文章,了解一下C语言的历史。

看起来我们从B语言到C语言再到C++语言都使用了这种语法...

我认为,声明多个某种“基本类型”的变量的方式是这种奇怪语法的根源:

int a, *b, c[3];

所以,a 只是一个 intb 是指向 int 的指针,c 是一个 int 数组...

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

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

关于如何解析这样的语句,SO C页面上有两个非常好的资源:

cdecl在某种程度上失败了-因为引用不是C的一部分-所以让我们尝试使用顺时针/螺旋规则来解析C声明。

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、大小为 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. int (&f(int (&arr)[3]))[3] -> f 是一个函数,接受类型为 int、大小为 3 的数组的引用作为参数,并返回类型为 int、大小为 3 的数组的引用

当然,这段代码应该被替换为对于我来说更容易阅读的版本:

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

这很有道理。感谢详细的回答!螺旋规则会非常有用。 - Izodine

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

让我们从内部开始。 (int (&arr)[3]) 部分意味着此函数将一个由3个元素组成的 int 数组的引用作为参数。这也是将被返回的相同的 arr
现在,其余的语法表示该函数应该返回一个由3个 int 组成的数组的引用。 f 是函数的名称。 int &f() 表示您返回对 int 的引用,但您需要返回固定大小的数组,因此应添加 [3]。括号包围 &f(...) 是因为在 c++ 中,您在变量名之后而不是类型名之后编写数组的大小,就像 Nawaz 在他的回答中所解释的那样。如果省略这些括号,编译器将解释 f 为引用数组,例如 int & f[3]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接