在读取复杂的C++类型时,有众所周知的螺旋和左右规则等,如
int (*(*foo)(char *,double))[9][20];
Foo是一个指针(改变方向,移出括号)
的函数,并返回(再次改变方向)。
指针指向
一个尺寸为9,20的二维数组(到达右端,外侧螺旋向左)。
整数。
但是,如果没有标识符,比如在定义函数参数的类型时,我如何处理这样的类型呢?
void foo(int *(*(* )(int(* )(int (* )(int))))())
^ ^ ^
identifiers omitted
我如何以一种直观的方式识别最内部的元素? 顺便说一下,即使是cdecl工具在最后这个例子中也给出了一个语法错误,但它确实可以编译。
当然,编译器有一个定义良好的方法来解析这样的胡言乱语。它怎么知道从哪里开始呢?
读取复杂类型的规则假设类型已经被解析过了(而且你知道 "最里面 "的点在哪里)。解析的规则是从外到内,和数学课上读复杂表达式一样。当你打到小括号的时候,给它起个名字,然后再来找它(除非它很简单,可以自己处理)。声明:我使用文本编辑器来定位匹配的小括号。 ;)
这个声明的另一个考虑是,一旦一个类型是一个函数,参数列表中的乱七八糟的东西就是一个单独的解析。例如,当解析 void (*)(big old mess)
,你有一个指向函数的指针。这一大堆乱七八糟的东西对于函数的签名来说是需要的,但对于理解你正在处理一个函数来说却不需要。
继续说说眼前的例子。
void foo(int *(*(* )(int(* )(int (* )(int))))())
在读完 void
和 foo
,你打了括号,里面有一个复杂的混乱。给这个乱七八糟的东西起个名字。
void foo( A )
哪儿 A
是 int *(*(* )(int(* )(int (* )(int))))()
. 所以你最外层的解析是一个单调函数,返回的是 void
,我们仍然需要解析参数。A
. 请注意,我们已经知道这段文字的总体目的是什么:它声明了一个名为 foo
. 其余类型没有名称,因为参数的名称是可选的。
A: int *( B )()
其中 B
是 *(* )(int(* )(int (* )(int)))
. 所以,参数要 foo
是一个最外层类型为空函数的东西,它返回一个指向 int
. 我们大概会发现 "something "是一个指针,但我们仍然需要解析一下 B
来证实这一点。(好了,往前跳一下,看到的是 B
以星号开头。这是一个指向这个空函数的指针)。)
B: *(* )( C )
其中 C
是 int(* )(int (* )(int))
. 这是一个指向单调函数的指针,它的参数是一些复杂类型,它的返回值是指向我们之前解析的东西(空值函数)的指针。与初始解析一样,我们发现了另一个开始读取的地方,因为乱七八糟的东西已经被推到了参数列表中。这个参数是 foo
是一个指向单数函数的指针,该函数的参数是一些复杂类型,其返回值是一个指向空函数的指针,该函数返回一个指向 int
.
C: int(* )( D )
哪儿 D
是 int (* )(int)
. 同样,乱七八糟的东西已经移到了参数列表中。这个层次的东西是一个指向单调函数的指针,它返回一个 int
.
D: int (* )(int)
最后,简单地说:一个指向单调函数的指针,它取一个 int
并返回一个 int
.
所以...
此声明 foo
是一个单调函数,返回 void
的指针,返回一个空值函数的指针,返回一个向 int
,其参数是一个指向单调函数的指针,返回的是 int
其参数是一个指向单调函数的指针,返回的是 int
其参数为 int
.
英文版本和代码一样容易理解,不是吗?:) 让我们试试更有条理的东西。
foo
void
int
int
int
int
Whew. 不要在家里这样做,孩子们。给你的中间类型起个名字,省得程序员费心。