c++most-vexing-parse

Most vexing parse even more vexing


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?


Solution

  • 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