提问人:template boy 提问时间:12/29/2012 最后编辑:Fabio says Reinstate Monicatemplate boy 更新时间:11/25/2021 访问量:8430
最令人烦恼的解析的目的是什么?
What is the purpose of the Most Vexing Parse?
问:
在维基百科上,我发现了这个:
A a( A() );
[这]可以消除歧义,因为
- 类 [] 的变量定义,采用类 [] 的匿名实例,或者
A
A
- 函数的函数声明,该函数返回 [] 类型的对象并接受单个(未命名)参数,该参数是返回类型 [] 的函数(并且不接受任何输入)。
A
A
大多数程序员期望第一个,但C++标准要求将其解释为第二个。
但是为什么?如果大多数 C++ 社区都期望前一种行为,为什么不将其作为标准呢?此外,如果不考虑解析歧义,上述语法是一致的。
有人可以开导我吗?为什么标准将此作为一项要求?
答:
没有特别的原因,除了[可能]K-ballo确定的情况。
这只是遗产。已经有了构造形式,所以当没有 ctor args 在起作用时,它似乎从来都不是需要的。int x;
T x;
事后看来,我想如果今天从头开始设计语言,那么 MVP 就不会存在......以及大量其他C++怪异之处。
回想一下,C++经过了几十年的发展,即使是现在,也只是由委员会设计的(另见:骆驼)。
这只是一个猜测,但这可能是因为使用给定的方法,您可以获得两种行为:
A a( A() ); // this is a function declaration
A a( (A()) ); // this is a variable definition
如果将其行为更改为变量定义,则函数声明将要复杂得多。
typedef A subfunction_type();
A a( A() ); // this would be a variable declaration
A a( subfunction_type ); // this would be a function declaration??
评论
A a( A() );
A a (A (*)())
a
A
void -> A
这是递归定义的语法的副作用。
它不是故意这样设计的。它被发现并记录为最令人烦恼的解析。
评论
假设 MVP 不存在。
您将如何声明函数?
A foo();
将是一个变量定义,而不是一个方法声明。你会引入一个新关键词吗?你会有一个更笨拙的函数声明语法吗?或者你宁愿拥有
A foo;
定义一个变量和
A foo();
声明一个函数?
您稍微复杂一些的示例只是为了与这个基本示例保持一致。说“所有可以解释为声明的东西,都将被解释为声明”比“所有可以解释为声明的东西,都将被解释为声明,除非它是一个单一的变量定义,在这种情况下,它是一个变量定义”更容易。
不过,这可能不是它背后的动机,而是一件好事。
对于 C++,这很简单:因为规则是在 C 中以这种方式制定的。
在 C 语言中,歧义只出现在 a 和一些相当晦涩的代码中。几乎没有人偶然触发它——事实上,它可能被认为是罕见的,除非是专门为演示这种可能性而设计的代码。然而,无论好坏,这种模棱两可的可能性意味着必须有人解决它——如果没记错的话,它是由丹尼斯·里奇(Dennis Ritchie)解决的,他下令任何可以被解释为声明的东西都将是声明,即使也有一个模棱两可的解释作为定义。typedef
C++ 添加了使用括号进行初始化以及函数调用作为分组的功能,这将歧义从晦涩变为常见。然而,改变它需要打破来自C的规则,正如大多数人所期望的那样解决这个特殊的歧义,而不创建六个更令人惊讶的歧义,除非你愿意完全放弃与C的兼容性。
评论
T(*b)[4];
T
考虑一下程序是否是这样的:
typedef struct A { int m; } A;
int main() { A a( A() ); }
这将是有效的 C,并且 C 的语法只允许一种可能的解释:被声明为函数。C 只允许初始化使用(而不是括号),不允许被解释为表达式。(函数样式强制转换是 C++ 独有的功能。这不是 C 语言中的“令人烦恼的解析”。a
=
A()
正如维基百科指出的那样,C++的语法使这个例子模棱两可。但是,如果你想让C++赋予这个程序与C相同的含义,那么,很明显,C++编译器将不得不像C编译器一样解释为一个函数。当然,C++可以改变这个程序的含义,使变量的定义 .然而,只有在有充分理由的情况下,才会在 C++ 中引入与 C 的不兼容,我想 Stroustrup 特别希望避免像这样潜在的静默破坏,因为它们会给迁移到 C++ 的 C 用户带来极大的挫败感。a
a
A
因此,C++ 也将其解释为函数声明,而不是变量定义;更一般地说,采用了这样的规则,即如果看起来像函数样式转换的东西可以在其句法上下文中被解释为声明,那么它应该是。这消除了在所有令人烦恼的解析情况下与 C 不兼容的可能性,确保不采用 C 中不可用的解释(即涉及函数样式强制转换的解释)。
Cfront 2.0 Selected Readings(第 1-42 页)提到了表达式声明歧义情况下的 C 兼容性问题,这是最令人烦恼的解析类型。
评论
T (*)()
a
a.f
a