最令人烦恼的解析

Most vexing parse

本文关键字:烦恼      更新时间:2023-10-16

我在这里看到了一个代码[问题#38]

#include <iostream>
struct Foo
{
  Foo(int d) : x(d) {}
  int x;
};
int main() 
{ 
  double x = 3.14;
  Foo f( int(x) );
  std::cout << f.x << std::endl;
  return 0;
} 

据说这段代码是病态的,因为Foo f( int(x) );将被视为函数声明,而不是Foo类型的对象声明。

据我所知,这是一个"最令人烦恼的解析"的例子。我的问题是语句Foo f( int(x) );中的语法int(x)是什么意思?到目前为止,我只看到了这样的函数声明:

  1. Foo f( int ); and

  2. Foo f( int x );

Foo f( int x );相同吗?

语句Foo f( int(x) );中的语法int(x)是什么意思?

x周围的圆括号是多余的,将被忽略。因此,int(x)与这里的int x相同,这意味着一个名为x的类型为int的参数。

Foo f( int x );相同吗?

是的。Foo f( int(x) );,是一个名为f的函数声明,返回Foo,接受一个名为x的类型为int的参数。

这是标准的解释。(dcl.ambig.res)/1:

(强调我的)

由于函数风格之间的相似性而产生的歧义Cast和[stmt]中提到的声明。也可以出现在声明的上下文。在这种情况下,选择是a函数声明,其中包含一组冗余圆括号参数名称和具有函数风格强制转换为的对象声明初始值设定项。就像在(支撑。[ambig], 的解决方案是考虑任何可能的构造

注意:声明可以是通过在参数周围添加括号显式消除歧义。可以使用复制初始化或列表初始化语法,或使用非函数风格的强制转换。

struct S {
  S(int);
};
void foo(double a) {
  S w(int(a));      // function declaration
  S x(int());       // function declaration
  S y((int(a)));    // object declaration
  S y((int)a);      // object declaration
  S z = int(a);     // object declaration
}

因此,int(x)将被视为(参数的)声明而不是函数样式的强制转换。

问题是,由于我不知道的原因,在原型中将参数名称包装到括号中是有效的。所以

Foo f(int(x));

可以解释为

Foo f(int x);

被认为是

Foo f(int);

真正的问题是,c++的作者,同样是出于我不知道的原因,认为对于几乎完全相同的语义(实例初始化)有两种不同的语法形式是很酷的。

这引入了一种语法歧义,这种歧义通过说"如果某物既可以是声明又可以是定义,那么它就是声明"来"解决",从而触发陷阱。

因此,c++解析器必须能够解析任意数量的令牌,然后才能确定其中第一个令牌的语义含义。

这显然不会有太大的问题,除了编译器的作者,但无论如何,这意味着谁也读c++代码理解它必须能够做同样的,对我们人类来说,这是困难的。