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
What Makes More Sense - Char* String or Char *String
How to Check If a C++ String Is an Int
Is There Any Reason to Use This-≫
What Does the Thread_Local Mean in C++11
How to Check If Given C++ String or Char* Contains Only Digits
In Stl Maps, Is It Better to Use Map::Insert Than []
The Differences Between Initialize, Define, Declare a Variable
Split a String into Words by Multiple Delimiters
Include Header Files Using Command Line Option
Is the 'Override' Keyword Just a Check For a Overridden Virtual Method
Implicit Type Conversion With Template
Const Int' Vs. 'Int Const' as Function Parameters in C++ and C