A confusing detail about the Most Vexing Parse
istream_iterator<int>(cin)
is exactly the same as istream_iterator<int> cin
but with superfluous parens. This declarator syntax was inherited from C, and I think even the inventor of C (Ken Thompson?) described it as a mistake.
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.
Most vexing parse
what does this syntax
int(x)
in the statementFoo 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 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
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
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.
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.
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"
Related Topics
Why How to Not Push_Back a Unique_Ptr into a Vector
Is There a Simple Way to Convert C++ Enum to String
Guaranteed Lifetime of Temporary in C++
Inline Functions VS Preprocessor Macros
Officially, What Is Typename For
When to Use Inline Function and When Not to Use It
Swapping Two Variable Value Without Using Third Variable
Opencv Point(X,Y) Represent (Column,Row) or (Row,Column)
How to Make Thread Sleep Less Than a Millisecond on Windows
Why How to Use Auto on a Private Type
What Does the Question Mark Character ('') Mean in C++
Shared_Ptr to an Array: Should It Be Used
What Happens to a Detached Thread When Main() Exits