最烦解析更烦

650*_*502 29 c++ most-vexing-parse

在下面的代码中

#include <map>
#include <string>

struct P2d {
    double x, y;
    P2d(double x, double y) : x(x), y(y) {}
};

double bar() {
    std::map<std::string, int> m;
    //P2d lp = P2d(double(m["x"]), double(m["y"])); // this works
    P2d lp(double(m["x"]), double(m["y"]));
    return lp.x;
}
Run Code Online (Sandbox Code Playgroud)

我测试的所有编译器都同意代码(未注释版本)无效,但我不明白为什么定义

 P2d lp(<double>, <double>);
Run Code Online (Sandbox Code Playgroud)

我使用的是不可接受的。

我记得规则是“如果它既可以是函数声明又可以是定义,那么它就是声明”,但我希望如果它不能是声明,那么它应该被解释为定义而不是给出错误。

我错过了什么?

bar*_*top 31

抓住你的椅子,因为它很有趣。您肯定知道 C++ 允许使用数组函数参数。所以你可以得到这个:

void foo(double s[2], double b[2]);
Run Code Online (Sandbox Code Playgroud)

这是显而易见的。一个可能的混淆步骤是替换类型和参数名称之间的空格,这也是允许的:

void foo(double(s[2]),double(b[2]));
Run Code Online (Sandbox Code Playgroud)

现在您可以想象可以非常简单地完成什么 - 将数字替换为const char*. 像这样:

void foo(double(s["x"]),double(b["y"]));
Run Code Online (Sandbox Code Playgroud)

这是无效的函数声明,但编译器认为它正是这个 - 声明。这正是您的代码发生的情况。

编辑:整个问题似乎源于对 C++ 标准中数组声明符的限制不够严格。数组 'size' 参数的唯一要求constexpr是应该转换为的值std::size_t(但它不会在语法分析级别检查,稍后会完成)。有关更多信息,请检查

  • 有时我想知道,如果实现者拒绝遵循委员会的决定,走上无意义的道路(比如允许自由函数的代码块级声明;我认为这没有合理的用途,并且从中所有混乱的最令人烦恼的解析),世界是否会变得更好开始)。 (5认同)