C++ 最令人烦恼的是,更令人烦恼的是

C++ 最令人烦恼的是,更令人烦恼的是,c++,most-vexing-parse,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&q

在下面的代码中

#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;
}
#包括
#包括
结构P2d{
双x,y;
P2d(双x,双y):x(x),y(y){}
};
双杠(){
std::map m;
//P2d lp=P2d(双精度(m[“x”]),双精度(m[“y”]);//这是可行的
P2d lp(双(m[“x”])、双(m[“y”]);
返回lp.x;
}
我测试过的所有编译器都同意代码(未注释版本)无效,但我不明白为什么定义是错误的

 P2d lp(<double>, <double>);
P2d-lp(,);
我用的是不能接受的

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


我错过了什么?

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

void foo(double s[2], double b[2]);
这是显而易见的。一个可能的混淆步骤是替换类型和参数名称之间的空格,这也是允许的:

void foo(double(s[2]),double(b[2]));
现在,您可以想象可以非常简单地完成的事情—用
const char*
替换数字。像这样:

void foo(double(s["x"]),double(b["y"]));
这是无效的函数声明,但是编译器认为它就是这个声明。这正是您的代码发生的情况

编辑:
整个问题似乎是由于C++标准中对数组声明器的不够严格的限制。数组“size”参数的唯一要求是
constepr
值,该值应转换为
std::size\u t
(但在语法分析级别上未进行检查,稍后再进行检查)。关于检查的更多信息

根据,我希望
P2d lp((double)m[“x”],(double)m[“y”])工作。@0x5453:有很多方法可以让它工作(大括号,或代码注释,或使用
static\u cast
)。我的问题是为什么这个代码不起作用…很有趣。我在搜索便笺时发现此便笺:。似乎这个答案是正确的?@MikaelH:这个来源是不明确的,规则说在这种情况下,函数声明占优势。我不明白的是,为什么问题中的代码(因为它不能作为函数声明进行解析,所以没有歧义)不是P2d实例的有效定义。我只能猜测,但我会想到与那篇文章相同的原因<代码>P2d lp(双精度(m[“x”])、双精度(m[“y”])被解析为
P2d lp(双m[“x”]、双m[“y”])=>
P2d lp(双*m,双*m)
OP认为,他想知道为什么编译器不能将其解析为函数声明并将其解析为变量定义(我猜是在第二步中)。编译器编写者需要回答的是,如果我们要求编译器回溯并尝试替代解析,那么所有的麻烦都会被打破。数组参数也是我的第一个想法,但这不是一个有效的数组参数,因为括号之间有
“x”
,而不是
3
。所以它不是一个有效的函数声明,为什么它被解析为一个函数声明(只是为了稍后给出错误)?例如在
intx(3)中括号内的部分作为参数无效,但在这种情况下,编译器只接受它作为整数的定义。线路在哪里?在哪里正式声明?@6502刚刚在标准中找到。这都是关于凌乱的数组声明器。我建议您阅读以下内容:有时我想知道,如果实现者拒绝遵循委员会的决定,沿着无意义的道路(比如允许自由函数的代码块级声明;我认为这是没有合理用途的,所有最麻烦的解析都是从这一点开始的),世界是否会变得更好,这个问题的标题绝对正确。