Most vexing parse even more vexing
Asked Answered
A

1

28

In the following code

#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;
}

all compilers I tested agree the code (un-commented version) is invalid but I fail to see why the definition

 P2d lp(<double>, <double>);

that I used is not acceptable.

I remember the rule was "if it can be both a function declaration and a definition then it's a declaration" but I expected that if it cannot be a declaration then it should be interpreted as a definition instead of giving an error.

What am I missing?

Animism answered 22/6, 2020 at 15:39 Comment(5)
According to this, I would expect P2d lp((double)m["x"], (double)m["y"]); to work.Apparel
@0x5453: there are many ways to get it working (braces, or the code commented, or using static_cast). My question is why this code is NOT working...Animism
Interesting. I found this searching for the note: #21625380. Seems like that answer is valid?Tambourine
@MikaelH: that source is ambiguous and the rule says that in such a case the function declaration prevails. What I don't understand if why the code in the question (that is NOT ambiguous because it cannot parse as a function declaration) isn't cosidered a valid definition of a P2d instance.Animism
I can only guess, but I would have thought the same reason as for that post. P2d lp(double(m["x"]), double(m["y"])); is parsed as P2d lp(double m["x"], double m["y"]); => P2d lp(double* m, double* m);Tambourine
A
30

Hold on to your chair since it's pretty funny. As you surely know C++ allows array function parameters. And so you can get this:

void foo(double s[2], double b[2]);

This is obvious. A possible obfuscation step is to replace spaces between type and parameters name which is also allowed:

void foo(double(s[2]),double(b[2]));

Now you can imagine what can be done pretty simply - replace numbers with const char*. Like this:

void foo(double(s["x"]),double(b["y"]));

This is invalid function declaration, nevertheless it is seen by the compilers as exactly this - declaration. This is exactly what happened to your code.

EDIT: The whole problem seems to arise from not strict enough restrictions on array declarators in C++ standard. The only requirement for array 'size' parameter is being constexpr value which is supposed to be converted to std::size_t (but it is not checked on the level of syntax analysis, it is done later on). For more on that check this

Acromegaly answered 22/6, 2020 at 16:0 Comment(8)
OP argues that he wants to know why the compiler couldn't then walk back on its parse as a function declaration and parse it as a variable definition (in a second step, I guess). What a compiler writer would need to answer is all the hell that would break loose if we were to require compilers to backtrack and try alternative parses.Cureall
Array parameters were my first thought also, but that is not a valid array parameter because there is "x" and not 3 between the brackets. So it's not a valid function declaration, why is it parsed as a function declaration anyway (just to give error later)? For example in int x(3); the part inside the parenthesis is invalid as parameters, but in this case the compiler simply accepts it as a definition of an integer. Where is the line? where is it stated formally?Animism
@Animism just found it in standard. It's all about messy array declarators. I suggest you read this: timsong-cpp.github.io/cppwp/dcl.decl#dcl.arrayAcromegaly
Indeed this seems the issue. Somehow I thought that the rules were similar to the ones used for SFINAE where a common trick is to use a negative sized array but it seems here the declaration is ruled out at a different level. If it passes the syntax check (where as you noted any constant expression is accepted) then it's a declaration and no backtracking is possible after that. In other words C++ syntax is just a nightmare :-D ...Animism
@Animism Yup, C++ is nightmare. Very beautiful, yet a nightmare. We should be thankful to the compilers' implementors ;)Acromegaly
Sometimes I wonder if the world would be better if implementers refused to follow committee decision down nonsense paths (like allowing code-block level declarations of free functions; something for which I can think to no sensible use and from which all the messy most vexing parse started).Animism
Given this answer, question's title is absolutely spot-on.Bissonnette
@Cureall - for automatically doing alternative parses: that's what GLR parsing is for.Bissonnette

© 2022 - 2024 — McMap. All rights reserved.