C++'S Most Vexing Parse Again

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

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

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.

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: why doesn't `g( ( f() ) );` call `f`'s default constructor and pass the result to `g`'s ctor that takes a `f`?

The first one declares a function called f that takes no parameters and returns g.

     g( f() );
// ^ ^ redundant set of parentheses

The second one is the same, with yet another redundant set of parentheses (remember that you can have as many declarations of the same functions as you wish). They are not always useless, though. You need them, say, to declare a function that returns a function pointer:

// function taking an int and returning
// a pointer to a function that takes a char
// and returns a g
g ( *f(int) )(char);
//^ ^ needed, syntax error without them

As for third:

When #1 and #2 are there, you've got a function declaration for f in mainand g myG( ( f() ) ); is parsed as a declaration of an object of type g, named myG and initialized with a result of a function call. You get a linker error because there's no definition for f.

When #1 and #2 are commented out, the type f is visible, and the disambiguation with parentheses kicks in:

g myG( ( f() ) )
// ^ ^ these force an expression

Without that pair, you'd get another function declaration.

What you want is this:

   ( g(f()) );
// ^ ^ must be an expression as declarations can't be parenthesized

or something less Lisp-y: static_cast<g>(f());

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.



Related Topics



Leave a reply



Submit