A Most Vexing Parse Error: Constructor With No Arguments

A most vexing parse error: constructor with no arguments

Although MyClass myObj(); could be parsed as an object definition with an empty initializer or a function declaration the language standard specifies that the ambiguity is always resolved in favour of the function declaration. An empty parentheses initializer is allowed in other contexts e.g. in a new expression or constructing a value-initialized temporary.

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.

Unclear most vexing parse

As you said, Foo foo2(); is a function declaration. For cout << foo2, foo2 would decay to function pointer, and then converts to bool implicitly. As a non-null function pointer, the converted result is true.

Without using boolalpha, the std::basic_ostream<CharT,Traits>::operator<< would output 1 for true.

If boolalpha == 0, then converts v to type int and performs integer output.

You can see it more clearer with usage of std::boolalpha.

cout << boolalpha << foo2  << endl;  // print out "true"

Most vexing parse confusion

Here:

auto dv = Timer();

You have an object of type Timer called dv that is being copy-initialized from a temporary (the expression on the right side of the = sign).

When using auto to declare a variable, the type of that variable is the same as the type of the expression that initializes it - not considering cv-qualifiers and references here.

In your case, the expression that initializes dv has type Timer, and so dv has type Timer.

Here:

int time_keeper(Timer());

You declare a function called time_keeper that returns an int and takes as its input a pointer to a function which returns a Timer and takes no argument.

And why isn't the argument Timer (*) () ?

Functions decay to pointers when passed as an argument, so the type of time_keeper is actually int(Timer(*)()).

To convince yourself, you could try compiling this little program:

#include <type_traits>

struct Timer { };
int main()
{
int time_keeper(Timer());
static_assert(
std::is_same<
decltype(time_keeper),
int(Timer(*)())
>::value,
"This should not fire!");
}

Here is a live example.

C++ Most vexing parse when a number literal is the argument?

but I would have thought the most vexing parse issue wouldn't arise as using a number literal of 256 couldn't be interpreted as a function.

That is correct, it is not the most vexing parse. The most vexing parse is formally handled in [dcl.ambig.res]:

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 a declaration.

The catch here is that you cannot initialize members using (), only = or {}, so naturally the ambiguity resolution does not apply.

C++'s most vexing parse again

In a function declaration, arguments of type array decay into pointers to the first element, arguments of type function decay into a function pointer, so the signature would be:

widget w( gadget(*)(), doodad(*)() );

That is, a function that takes as the first argument a pointer to a function taking no arguments and returning gadget, that takes as second argument a pointer to a function taking no arguments and returning a doodad and that the function itself returns a widget

There are even more interesting or confusing cases, like:

// assume 'x' is a variable defined somewhere:
widget w(gadget(x));

How could that be interpreted as a function declaration? I mean, x is a variable, right? Well, when declaring a variable you can add extra parenthesis, so gadget x; and gadget (x); both declare the same variable x. The same applies to function arguments so the code above looks like a declaration of a function that takes a first argument named x of type gadget and returns a widget...

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();
}

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.



Related Topics



Leave a reply



Submit