最令人烦恼的解析
Most vexing parse
我在这里看到了一个代码[问题#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)
是什么意思?到目前为止,我只看到了这样的函数声明:
Foo f( int );
andFoo 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++代码理解它必须能够做同样的,对我们人类来说,这是困难的。
- 最烦人的解析甚至更令人烦恼
- 最令人烦恼的解析会阻止在类内初始化 std::vector<int>
- C++ 当数字文字是参数时,最令人烦恼的解析?
- 大多数令人烦恼的解析,并访问阵列
- STL Scott Meyers的烦恼分析
- (为什么)这是一个令人烦恼的解析示例吗?
- C++最令人烦恼的矢量元素交换
- C++模板奇怪的语法让我烦恼
- 保留动态分配的数组而不为删除而烦恼的最佳方法
- 可以X X(T ..)导致函数声明,并具有烦恼的解析
- 大多数令人烦恼的解析都带有限定 id - 或不
- 强制将最令人烦恼的解析的歧义消除为函数声明
- 为什么要在 if 条件下进行令人烦恼的解析
- 解析python文件时出现令人烦恼的Ctrl+M问题
- C++多个包含烦恼
- 令人烦恼的C++gcc警告消息
- (c++)面向对象——用类拓展——初学者的烦恼
- 模板函数的小烦恼
- 这是一个多么令人烦恼的解析
- 最令人烦恼的解析实例与std::string和char*