19

I was reading an SO post where one user made the following comment:

Also note that ArrTest<int> ar(); uses most vexing parse.

But another user said the opposite:

ArrTest<int> ar(); is not the "most vexing parse". It's just a function declaration. It's certainly vexing for beginners, but, as the page you linked to indicates, the "most vexing parse" is more convoluted.

The code example from that post is given below for reference:

template <class ItemType>
class ArrTest {
public:
    ArrTest();
private:
    ItemType* info;
};
//some other code here

int main() {
    ArrTest<int> ar();  //DOES THIS USE THE MOST VEXING PARSE?
    return 0;
}

My first question is that is the concept of "most vexing parse" formally defined by the C++ standard. My second question is that does the statement ArrTest<int> ar(); uses most vexing parse. That is, which of the above two quoted comments is technically correct?


This also seem to suggest that MyObject object(); is most vexing parse.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • 7
    In the C++17 working draft, there is no occurrence of the word "vexing". – Daniel Langr Apr 20 '22 at 09:56
  • 1
    I think [this answer](https://stackoverflow.com/a/7009105/10871073) is an excellent one in terms of how MVP is *explained* and laid down in the C++ Standard. Not sure if that would qualify this as a duplicate question, though. – Adrian Mole Apr 20 '22 at 10:01
  • It's "vexing" but perhaps not the *most* vexing. :-) And you can now use `{}` for initialization, to avoid the whole problem, – BoP Apr 20 '22 at 10:05
  • 5
    I've never seen a least vexing parse. – Retired Ninja Apr 20 '22 at 10:08
  • @RetiredNinja. You just didn't realize you saw it because you weren't vexed. – Mad Physicist Apr 20 '22 at 20:09
  • Couldn't this statement be misinterpreted as `(ArrTest < int) > ar();`, until the compiler realizes that `ArrTest` and `int` are type names and not variables? – dan04 Apr 20 '22 at 21:28

2 Answers2

17

is the concept of "most vexing parse" formally defined by the C++ standard.

No. There is no concept of "most vexing parse" defined in the C++ standard. The standard does define the grammar from which the ambiguities arise, and it defines the rule that resolves the ambiguities, but it doesn't name the ambiguities.

According to Wikipedia: "The term "most vexing parse" was first used by Scott Meyers in his 2001 book Effective STL.". The example in the book is:

Item 6. Be alert for C++'s most vexing parse.

ifstream dataFile("ints.dat");
list<int> data(istream_iterator<int>(dataFile), // warning! this doesn't do
               istream_iterator<int>());        // what you think it does

The way I would describe "MVP" is that there is an intention to declare a variable, with passed argument(s), but you end up actually writing a function declaration and the intended arguments turn out as parameter declarators.


does the statement ArrTest ar(); uses most vexing parse.

The book explicitly mentions this ambiguity as well:

If you've been programming in C++ for a while, you've almost certainly encountered another manifestation of this rule. How many times have you seen this mistake?

class Widget {...}; // assume Widget has a default constructor
Widget w();         //'uh oh...

Given that the author who came up with the name for the ambiguity considers this as another manifestation - as opposed to the same manifestation - of a language rule, I would say that the example in question is not the "MVP". It's another, similar, and in my opinion less vexing ambiguity.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • 1
    The explanation for the last example `Widget w();` that you gave, i didn't understand. I mean, say when i write `Widget w();` i wanted to create a widget object but accidentally i created a declaration for function named `w`. So this is clearly a use of most vexing parse. I mean you wrote: *"another manifestation as opposed to the same manifestation"*. Is it because the author wrote: *"with passed argument(s)"*? – Jason Apr 20 '22 at 11:00
  • @Anya I wrote "with passed arguments". The author wrote the example that has the arguments that they described as the "most vexing parse" as opposed to their widget example that the author described as "a veritable rite of passage for C++ programmers". – eerorika Apr 20 '22 at 11:08
  • 2
    The author wrote: *" you've almost certainly encountered another manifestation of this rule."* and then gave the `Widget w();` example. Since the author himself said that this example is a manifestation of this(most vexing parse) rule, so what is the problem here. I mean, this uses most vexing parse so the answer to my second question should be "yes it uses most vexing parse" , doesn't it? Or am i missing something. – Jason Apr 20 '22 at 11:25
  • 1
    @Anya No. "This rule" is not "most vexing parse". "This rule" is "[dcl.ambig.res] ... the resolution is to consider any construct that could possibly be a declaration a declaration." – eerorika Apr 20 '22 at 11:37
  • Ok, so the rule that [dcl.ambig.res] that you quoted, can also be applied to say: `TimeKeeper time_keeper(Timer());`? I mean here also, the construct can possibly be a declaration so it is considered as a function declaration. I mean when we already have [dcl.ambig.res] so why we need the MVP? Btw, the timer_keeper example is from [wikipedia](https://en.wikipedia.org/wiki/Most_vexing_parse). – Jason Apr 20 '22 at 11:42
  • 1
    @Anya `so why we need the MVP` What do you mean by "need"? We need to understand MVP in order to understand the ambiguity and how it is resolved. – eerorika Apr 20 '22 at 11:45
  • I mean that for the construct `TimeKeeper time_keeper(Timer());`, [dcl.ambig.res] applies and so it is taken to be a declaration. Now, the problem is already resolved by [dcl.ambig.res]. So, why MVP is needed here? since we [dcl.ambig.res] was able to resolve the issue. – Jason Apr 20 '22 at 11:48
  • 2
    @Anya Again, I don't understand your question. There are apparent ambiguities in the grammar of C++. [dcl.ambig.res] rule resolves those ambiguities. When a programmer who isn't aware of such ambiguity expects the resolution to be different, they are confused. MVP is a complex (most vexing) example of such ambiguity. These ambiguities are not what we "need". They are something that we need to understand in order to overcome problems when we encounter those ambiguities. – eerorika Apr 20 '22 at 11:55
  • 2
    @Anya It's not a rule, it's a name given to a sometimes surprising phenomenon in order to be able to talk about it. It's called "vexing" because the resolution of the ambiguity can be vexing. Countless programmers have spent hours trying to figure out why the compiler thinks that an obvious variable declaration declares a function. – molbdnilo Apr 20 '22 at 12:12
3

As the author of the second quote in the question, yes, it's a bit pedantic, but applying the term "most vexing parse" to int f();, which every C++ programmer will recognize as a function declaration, is misleading.

When you see int f(); you should thing "function declaration". And when you need to write a declaration of a function that takes no arguments and returns int you should think of int f();. That's how you do it. On the other hand, when you see something like TimeKeeper time_keeper(Timer());, maybe you should think "function declaration", because that's what it is, but if you want to declare a function that takes an argument of type Timer and returns TimeKeeper you should not think of TimeKeeper time_keeper(Timer());. That way lies madness. Or, at best, vexation.

"Most Vexing Parse" is useful as a label that says "you've done something confusing here". int f(); is not confusing; TimeKeeper time_keeper(Timer()); is. On the other hand, if "most vexing parse" is applied to any application of that disambiguation rule, then you need a term for "most vexing parse that's useful and necessary" and another for "most vexing parse that you should not have written". Simpler is better.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • 3
    *"which every C++ programmer will recognize as a function declaration"* I don't agree with this. Something that is obvious to you(one person) may not be obvious to me(another person). I mean obviousness is a subjective term. It doesn't matter if one is able to correctly understand that `int f();` is a declaration. If one is able to understand a particular thing, that doesn't imply that everyone else will also be able to. doesn't matter how trivial that thing is. The term MVP seems like a very opinionated term to me. – Jason Apr 20 '22 at 13:45
  • I mean if something is applicable to the complicated case like the `time_keeper` example above then it should naturally be applicable to the simple case like `Widget` example as well. Just making a distinction based on one's opinion of what other might think isn't right. – Jason Apr 20 '22 at 13:49
  • 3
    @Anja The point of recognizing `int f();` as a function declaration is, that this is the way functions have been declared in both C and C++ since the 60's (i.e. before C++ was even born). It was when C++ needed a way to invoke a constructor call (possibly with arguments), and when the syntax `myClass instance();` was repurposed for that end, that the most vexing parse was introduced into the language (a mistake, imho). As such, any experienced C programmer can be expected to always read a function declaration where possible, just as the most vexing parse rule prescribes. – cmaster - reinstate monica Apr 20 '22 at 19:24
  • 1
    @cmaster-reinstatemonica My point is that a rule isn't(or rather shouldn't be) based on whether experienced programmers are correctly able to understand it and the beginners are not. Saying that everyone will straightaway recognize `int f();` as a function declaration is nothing but ignorance. At the most, one can say that most programmers will recognize it, but one cannot say that all programmers will. – Jason Apr 21 '22 at 16:32
  • @Anya Indeed. The "every" is a bit of a hyperbole... I just wanted to help you understand the history that may cause experienced hands to utter such overstatements. It's more productive to understand their reasoning than to argue about the impreciseness of their statement. – cmaster - reinstate monica Apr 21 '22 at 18:16
  • The 60s might be a little too far back, since **C** first appeared in 1972. Had C++ strictly used `Foo f(void);` to indicate a function with no parameters, then `Foo f();` could be an unambiguous `f` object of type `Foo` that was default constructed. For better or worse, `Foo f();` was intentionally chosen to express a function declaration with no parameters. – Eljay Jul 18 '22 at 12:48