Most Vexing Parse

What is the purpose of the Most Vexing Parse?

Let's say MVP didn't exist.

How would you declare a function?

A foo();

would be a variable definition, not a method declaration. Would you introduce a new keyword? Would you have a more awkward syntax for a function declaration? Or would you rather have

A foo;

define a variable and

A foo();

declare a function?

Your slightly more complicated example is just for consistency with this basic one. It's easier to say "everything that can be interpreted as a declaration, will be interpreted as a declaration" rather than "everything that can be interpreted as a declaration, will be interpreted as a declaration, unless it's a single variable definition, in which case it's a variable definition".

This probably isn't the motivation behind it though, but a reason it's a good thing.

Most vexing parse C++11

what exactly this line does

It creates a temporary X, value-initialising it by calling the default constructor, and then uses that to initialise a Y variable, calling the const X& conversion constructor.

where is connection to Most vexing parse

If you were to try to write this using old-school initialisation syntax

Y y (X());

then the so-called "most vexing parse" would interpret this as a function, rather than a variable, declaration: a function called y, with return type Y and a single parameter, whose type is a (pointer to a) function returning X.

You could add extra parentheses, so that it can't be interpreted as a function declaration:

Y y ((X()));

or, since C++11, you can use brace-initialisation as your example does.

Most vexing parse [duplicate]

what does this syntax int(x) in the statement Foo f( int(x) ); mean?

The parentheses around x are superfluous and will be ignored. So int(x) is the same as int x here, which means a parameter named x with type int.

Is it the same as Foo f( int x );?

Yes. Foo f( int(x) );, is a function declaration which is named f, returns Foo, takes one parameter named x with type int.

Here's the explanation from the standard. [dcl.ambig.res]/1:

(emphasis mine)

The ambiguity arising from the similarity between a function-style
cast and a declaration mentioned in [stmt.ambig] can also occur in the
context of a declaration. In that context, the choice is between a
function declaration with a redundant set of parentheses around a
parameter name and an object declaration with a function-style cast as
the initializer. Just as for the ambiguities mentioned in
[stmt.ambig], the resolution is to consider any construct that could
possibly be a declaration
.

Note: A declaration can be
explicitly disambiguated by adding parentheses around the argument.
The ambiguity can be avoided by use of copy-initialization or
list-initialization syntax, or by use of a non-function-style cast.

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
}

So, int(x) will be considered as a declaration (of the parameter) rather than a function style cast.

Most vexing parse with array access

The reason is because in the context of a function declaration, the compiler will interpret std::string(argv[0]) as std::string argv[0], i.e. a declaration of a zero-sized array as the function parameter named argv (overshadowing the argv from main, as this is a different scope), which then is equivalent to a pointer by array-to-pointer-decay.

Therefore, std::stringstream ss(std::string(argv[0])); means the same as std::stringstream ss(std::string* argv);

Edit: As it got correctly annotaded in the comments, zero-sized array declarations are invalid in C++, rendering the program ill-formed. When compiling this code with -pedantic flags (GCC and clang), warnings will be issued. Visual Studio even produces a compilation error. For any other array index than 0, the argumentation above however still holds.

How can I avoid most vexing parse with direct value initialization?

Use copy initialisation and rely on C++17's guarantee that copy elision will happen.

For example:

struct Foo
{
Foo() = default;
Foo(Foo const&) = delete;
};

int main()
{
auto f = Foo();
}

https://godbolt.org/g/9tbkjZ

Most vexing parse

This is due to the fact that TimeKeeper time_keeper(Timer()); is interpreted as a function declaration and not as a variable definition. This, by itself, is not an error, but when you try to access the get_time() member of time_keeper (which is a function, not a TimeKeeper instance), your compiler fails.

This is how your compiler view the code:

int main() {
// time_keeper gets interpreted as a function declaration with a function argument.
// This is definitely *not* what we expect, but from the compiler POV it's okay.
TimeKeeper time_keeper(Timer (*unnamed_fn_arg)());

// Compiler complains: time_keeper is function, how on earth do you expect me to call
// one of its members? It doesn't have member functions!
return time_keeper.get_time();
}

Most vexing parse even more vexing

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



Related Topics



Leave a reply



Submit