递归变量声明

44

我刚刚在 folly/ManualExecutor.h 中看到了这个黑魔法。

TimePoint now_ = now_.min();

在我使用 grep 命令搜索整个库源代码后,我没有看到变量 now_ 的定义出现在这之外的任何地方。这是怎么回事?这实际上是一种递归变量声明吗?


3
如果有TimePoint的文档链接,或者加上TimePoint :: min()的声明(从.h文件中复制相关行即可,如果编译通过,则必须拥有该文件),我认为这个问题可以得到改进。 - hyde
请参阅:https://dev59.com/AHRC5IYBdhLWcg3wW_pk - Cody Gray
9
另一种混淆代码的方法。 - A.S.H
1
看起来有点像 Java 中的 Runtime runtime = Runtime.getRuntime();... - MD XF
顺便说一句,我偶然发现了这个stackoverflow问题,并修补了它,使其不再那么不透明:https://github.com/facebook/folly/commit/b727acf4391c4f3300ab0348bf1032a02999b408#diff-30beff23525b19a3404dbfc49d84d25f - Louis Brandy
显示剩余2条评论
2个回答

63

那段代码很可能等同于这个:

TimePoint now_ = TimePoint::min();

也就是说,min()是一个静态方法,使用实例调用它与像这样调用它是相同的,只是实例用于确定类型。没有黑魔法参与,这只是做相同事情的两个语法。

至于为什么问题中的代码可以编译:左侧已经声明了now_,因此当它在右侧用于初始化时,编译器已经知道它的类型,并且能够调用静态方法。试图调用非静态方法应该会产生错误(请参见下面@BenVoigt的评论)。

正如你不得不提出这个问题的事实所示,问题中的语法并不是最清晰的。如果类型名称很长,在成员变量声明中使用这种语法可能很诱人,而且可能在具有初始值设定项(如问题代码)的成员变量声明中是可行的。在函数内部的代码中,auto是减少重复的更好方式。


21
从编译器的角度来看,这两种写法是等价的。但在代码审查中,只有其中一种是可以接受的。让读者猜猜是哪一种,留给他们自己去练习。 - Cody Gray
12
@CodyGray,是的,大家都知道你对那四个恶心的点的厌恶。但请你理性一些:有时候::是最好的选择! - Yakk - Adam Nevraumont
5
非静态情况下的分析 -- 初始化器的值计算在复制构造函数调用之前按顺序进行(这种语法是拷贝初始化),因此构造函数尚未开始执行,因此对象的生命周期尚未启动。标准第3.8节规定:“在对象的生命期开始之前但在分配对象所需的存储空间之后,可以以有限的方式使用引用原始对象的任何 glvalue。如果使用该 glvalue 调用对象的非静态成员函数,则程序具有未定义行为。” - Ben Voigt
OP引用的代码实际上是一个非静态数据成员,其中auto不可用。 - T.C.
@hyde min是静态的。问题在于now_实际上是某个类的非静态数据成员,而now_.min()实际上是它的默认成员初始化器。 - T.C.
显示剩余2条评论

14

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