Most Vexing Parse Confusion

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.

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 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

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.

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

How do I determine if a given date is the Nth weekday of the month?

You could change the check of the week so the function would read:

private bool NthDayOfMonth(DateTime date, DayOfWeek dow, int n){
int d = date.Day;
return date.DayOfWeek == dow && (d-1)/7 == (n-1);
}

Other than that, it looks pretty good and efficient.

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.

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