我不明白为啥会这样编译
Posted
技术标签:
【中文标题】我不明白为啥会这样编译【英文标题】:I do not understand why this compiles我不明白为什么会这样编译 【发布时间】:2020-03-28 11:07:27 【问题描述】:我当然遗漏了一些东西,但我不明白为什么会编译(同时使用 g++ 和 clang++):
struct A
;
struct B
;
int main()
A a(B);
首先,B
是一个类型...不是一个值。我应该如何解释这段代码?
【问题讨论】:
这被称为Most Vexing Parse @alterigel 真的吗?在这种情况下,没有歧义。它只能是一个函数声明。不是A a(B());
,它可以是变量定义或函数声明。
你会惊讶地发现struct A; int main() A(foo);
compiles as is,即使foo
没有说出任何名字。
@alterigel -- 这不是最令人头疼的解析。查看您链接到的页面上的示例。这只是一个函数声明。
@PeteBecker,最好解释一下为什么这不是 MVP,而不是仅仅断言它不是,我相信 walnut 已经在上面做了。
【参考方案1】:
它被解释为一个名为a
的函数的声明,它接受一个B
类型的参数并返回A
。
【讨论】:
这就是为什么它是 Most 和 Vexing。一个解决方案:(并不是说它实际上解决了任何问题,因为它暴露了糟糕的结构)A aB;
@user4581301 -- 它不是最令人头疼的解析。它只是一个函数声明。
最奇怪的是C++不允许嵌套函数,但确实允许在函数内声明。
听起来像是向 C++ 添加对嵌套函数的支持的好动机;它们不仅有用,而且会将这种奇怪的疣变成合理的设计:)
@Brian “有点违反直觉”可能是 C++ 的座右铭 :)。至于前向声明,我认为它们不支持本地函数,并称之为完成。【参考方案2】:
这只是一个函数声明,将a
声明为一个返回A
并采用B
类型的未命名参数的函数。
这是有效的,因为在函数定义中允许函数声明而不是函数定义。
【讨论】:
【参考方案3】:这个问题被称为most vexing parse。 A a(B);
行可以解释为一个名为 a
的函数的声明,它返回一个 A
类型的对象并采用 B
类型的未命名参数。
避免此问题的一种方法是使用在 C++11 中引入的 统一初始化 语法,该语法包括使用大括号而不是括号:A aB;
返回错误。该行现在被解释为使用B
初始化的变量声明,这是一个类型而不是一个值。
这里有更多信息:
The Most Vexing Parse: How to Spot It and Fix It Quickly
【讨论】:
我认为这不应该被称为“最令人头疼的解析”。它只是一个通常的函数声明,因为它也存在于 C 中。没有必要的歧义解决,因为该行只能是一个函数声明,没有别的。看看你的链接。示例都与此不同。 虽然确实如此,但它与最令人头疼的解析有关。只是这还包括一个错字,其中单独使用类型名称而不是变量或构造函数调用,这可能是最初的意图。 是的,“Most Vexing Parse”在这种情况下是一个有用的答案,即使问题中的实际情况只是“Slightly Vexing Parse”。 @wlanut:空结构struct A ;
在标准 C 中无效,即使某些编译器允许它们。放下牙套,那里就不会有问题了。此外,在 C 中,声明或定义 struct A
不会创建类型名称 A
(您必须为其添加前缀 struct
,或者在使用 A
之前的某处添加 typedef struct A A;
而不使用 struct
前缀)。同样在 C 语言中,函数声明没有替代解析——使用 type name(...);
根本不可能是变量定义;它始终是函数声明(或无效)。问题中的代码在 C 中无效。
@jpa,我在任何地方都找不到任何关于“Slightly Vexing Parse”的文章。这个名字只是口头传统吗?我想了解更多。以上是关于我不明白为啥会这样编译的主要内容,如果未能解决你的问题,请参考以下文章
为啥我们在编译组合 GAN (SRGAN) 网络时使用两个损失