I do not understand why this compiles
Asked Answered
W

3

81

I'm certainly missing something, but I do not understand why this compiles (with both g++ & clang++):

struct A
{
};
struct B
{
};

int main()
{
  A a(B);
}

First of all, B is a type... not a value. How should I interpret this code?

Whaling answered 3/12, 2019 at 17:40 Comment(7)
This is known as the Most Vexing ParseCastiron
@alterigel Is it really? In this case there is no ambiguity. It can only be a function declaration. It is not A a(B()); which could be a variable definition or function declaration.Impasto
You'd be surprise to know that struct A{}; int main() { A(foo); } compiles as is, even if foo doesn't name anything.Kristof
Does this answer your question? Most vexing parse confusionPrecognition
@alterigel -- this is not the most vexing parse. Look at the examples on the page that you linked to. This is simply a function declaration.Indissoluble
@PeteBecker, it might be better to explain why this isn't MVP instead of just asserting that it is not, which I believe walnut already did above.Bolshevism
@IslamEl-Rougy, yes using {} for constructors avoid this. I have no problem with the answers I got... although this was certainly my most vexing "question" :-)Whaling
V
87

It's interpreted as the declaration of a function named a, which takes one argument of type B and returns A.

Vivavivace answered 3/12, 2019 at 17:41 Comment(10)
And that is why it is Most and Vexing. A solution: (not that it actually solves anything since it exposes the bad construction) A a{B};Votary
@Votary -- it's not the most vexing parse. It's simply a function declaration.Indissoluble
Right. Most vexing parse has more meat in the accidental function call.Votary
The weirdest part about it is that C++ does not allow nested functions, but does allow declarations inside a function.Jori
@Jori just like everything else in C++, it has its valid use cases.Kristof
Sounds like a good motivation for adding support for nested functions to C++; not only would they be useful, they'd turn this odd wart into a reasonable design :)Sunflower
@JeremyFriesner But we couldn't change the meaning of local function declarations as it is currently, because that would break existing code. That makes the case for nested function definitions somewhat less compelling. Particularly since we can use lambdas now.Vivavivace
@Brian My proposed change would be allowing inline-code of the form void Foo() { void Bar() {printf("Bar!\n");} printf("Foo!\n"); } ... which wouldn't break compatibility simply because code of that form already doesn't compile, and therefore no code like that exists to be broken. Not that I'm willing to actually try to get that into the language, rather I'm just daydreaming :)Sunflower
@JeremyFriesner Yeah, but it's a little bit counterintuitive that a nested declaration would declare the function at namespace scope whereas a nested definition would create a local function. How do you forward-declare a local function, then?Vivavivace
@Brian "a little bit counterintuitive" could be C++'s motto :). As for forward declarations, I would just deem them Not Supported for local functions, and call it done.Sunflower
B
15

It's simply a function declaration declaring a to be a function returning A and taking one unnamed parameter of type B.

It is valid because function declarations as opposed to function definitions are allowed within function definitions.

Bruit answered 3/12, 2019 at 17:48 Comment(0)
P
13

This issue is known as the most vexing parse. The line A a(B); can be interpreted as the declaration of a function named a returning an object of type A and taking an unnamed parameter of type B.

One way to avoid this issue is to use the uniform initialization syntax which was introduced in C++11, which consists in using braces instead of parenthesis: A a{B}; returns an error. The line is now interpreted as a variable declaration initialized with B, which is a type instead of a value.

Here's more information:

The Most Vexing Parse: How to Spot It and Fix It Quickly

Preinstruct answered 3/12, 2019 at 18:4 Comment(6)
I don't think this should be called "most vexing parse". It is just a usual function declaration as it also exists in C. There is no ambiguity resolution necessary because the line can only be a function declaration, nothing else. Look at your link. The examples are all different from this.Impasto
While that's true, it is related to the most vexing parse. It's just that this also included a typo where a type name was used alone instead of a variable or a constructor call, as was probably the original intent.Hysteria
Yeah, "Most Vexing Parse" is an useful answer in this case, even though the actual case in the question is just "Slightly Vexing Parse".Trilby
@wlanut: The empty structures struct A { }; are not valid in standard C, even if some compilers allow them. Drop the braces and there wouldn't be a problem there. Also, in C, declaring or defining struct A does not create a type name A (you must prefix it with struct, or add typedef struct A A; somewhere before A is used without the struct prefix). Also in C, there is no alternative parse to the function declaration — using type name(...); simply cannot ever be a variable definition; it is always a function declaration (or invalid). The code in the question is not valid in C.Corrinecorrinne
@jpa, I can't find anything written about "Slightly Vexing Parse" anywhere. Is this name just oral tradition? I'd like to read more about it.Clonus
@KeithRussell It was just a play on words. This question is a simpler case that is related to the well known "Most Vexing Parse". That's why I referred to this question as "Slightly Vexing Parse".Trilby

© 2022 - 2024 — McMap. All rights reserved.