2
#include <iostream>

class Base
{
    public:
        int id;
};

int main()
{
    Base b();
    b.id = 1; 
}

What is wrong with the object creation in the code above? What is the difference between Base b() and Base b?

kaspersky
  • 3,959
  • 4
  • 33
  • 50
  • It would help if you had a constructor, eg Base(int id); – QuentinUK Mar 08 '13 at 18:36
  • @Cheersandhth.-Alf I'm sure it is a duplicate, but this is not the most vexing parse. – juanchopanza Mar 08 '13 at 18:36
  • @QuentinUK no, it wouldn't – SomeWittyUsername Mar 08 '13 at 18:37
  • 1
    @juanchopanza: it is, of course, unless you accept an impractical, stupid, idiotic, braindead, retarded, etc. etc. distinction based on the formal syntax (i'm sure Scott didn't mean that, but he couldn't foresee being interpreted by the very literal-minded non-thinking) – Cheers and hth. - Alf Mar 08 '13 at 18:38
  • @Cheersandhth.-Alf: This is not about idiotic distinctions: simply, that statement is not ambiguous. It is just a bogus attempt to invoke the constructor, which would be illegal, OR a declaration. Therefore, it is a declaration. There's no parsing problem here. The parsing problem is when the syntax is actually ambiguous. I'm not sure why you consider this to be a stupid distinction. – Andy Prowl Mar 08 '13 at 18:40
  • @Cheersandhth.-Alf I second that. I'd say this example is clearer than the original one – SomeWittyUsername Mar 08 '13 at 18:41
  • @AndyProwl: you're wrong, there is a parsing problem. the expression `Base()` is perfectly valid for default-constructing an object of type `B`, in the same way as `Base(42)` is valid if there is such a constructor, and so on. the parsing problem is to recognize it as a constructor call, and the rule in C++ is to parse it as a function declaration if at all syntactically possible. – Cheers and hth. - Alf Mar 08 '13 at 18:42
  • @Cheersandhth.-Alf: `Base()` maybe, but not `Base b()` – Andy Prowl Mar 08 '13 at 18:43
  • ...and explicitly adding the constructor `Base(){}` will result in the same error, emphasizing the ambiguity – SomeWittyUsername Mar 08 '13 at 18:44
  • @AndyProwl: do you recognize any similarity between the transformation `auto b = Base(42);` --> `Base b(42);` and the transformation `auto b = Base();` --> `Base b();` (i mean similarity, not the difference that the latter's rhs declares a function) – Cheers and hth. - Alf Mar 08 '13 at 18:45
  • Uh, what are we arguing about? `Base b();` is the textbook example of the MVP. Was there an edit that I missed or something? – Seth Carnegie Mar 08 '13 at 18:48
  • @SethCarnegie: [I really don't think so](http://en.wikipedia.org/wiki/Most_vexing_parse). MVP is about a declaration being preferred over an object construction when both are syntactically valid. Here, `Base b();` is not a syntactically valid way of constructing an object of type `Base`. Therefore, there is no ambiguity. – Andy Prowl Mar 08 '13 at 18:50
  • @AndyProwl: i think perhaphs what you're not getting is that it *could be*, except for the parsing problem, and also, that the distinction you're making is of negative practical value... :-( – Cheers and hth. - Alf Mar 08 '13 at 18:51
  • @Cheersandhth.-Alf: I got that, I mean, if C++ were different than it is then this could be MVP. I'm talking about what C++ is today and this is not MVP – Andy Prowl Mar 08 '13 at 18:52
  • 1
    @AndyProwl ohhhhhh, I see what you mean. However, by the same token, I could say `TimeKeeper time_keeper(Timer());` isn't a syntactically valid way of declaring an object either, because it's a function, therefore the MVP doesn't exist, right? I mean, if I were trying to argue. – Seth Carnegie Mar 08 '13 at 18:52
  • @SethCarnegie: Not sure I get your point. `TimeKeeper time_keeper(Timer());` is a syntactically meaningful way of constructing an object called `time_keeper` and pass the result of `Timer()` to its constructor. However, it is also a valid function declaration, hence the ambiguity. Which makes this a case of MVP. – Andy Prowl Mar 08 '13 at 18:53
  • @AndyProwl I don't know how it's syntactically meaningful if you can't do it. It seems like it's meaningful in the same way as `Base b()` is meaningful. – Seth Carnegie Mar 08 '13 at 18:55
  • @SethCarnegie: From the point of view of the parser it is syntactically meaningful. The grammar says an object construction *can* be expressed that way, while it can't be expressed by putting empty parentheses. Now the fact that there's another grammar rule which says that also something else can be expressed in the exact same way (function declaration) gives rise to ambiguity. And then there's a rule saying that something which can be parsed as a declaration and as something else should be considered a declaration. This is where the MVP has its roots – Andy Prowl Mar 08 '13 at 18:58
  • @AndyProwl so I guess there's two MVPs: one of the mind and one of the compiler. – Seth Carnegie Mar 08 '13 at 18:59

2 Answers2

3

This

Base b();

is parsed as a function declaration of a function called b() that returns a Base object. You need this:

Base b;

This will instantiate a Base object and call its default constructor. Note that this will not zero initialize base::id. You can fix this by providing a default constructor that does that:

class Base
{
    public:
        Base() : id(0) {}
        int id;
};

and instantiate in the same way:

Base b;
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • i think, if one feels that it's better to produce a new answer than to refer to the countless existing answers, then a more complete answer could be expected (i.e., what's missing in the existing ones that's covered here) – Cheers and hth. - Alf Mar 08 '13 at 18:36
2

The problem is that you are not instantiating an object, but rather declaring a function. This:

Base b(); // Function declaration! (not what you want)

Declares a function b() that returns an object of type Base and accepts no argument. Therefore, when you later try to access the member id, the compiler emits an error, because functions do not have members:

b.id = 1; // ERROR! b is a function, accessing member "id" makes no sense

If you want to create an instance of Base, instead, just remove the parentheses:

Base b; // Object instantiation! (what you want)

Notice that in C++11 you can use the uniform initialization syntax to create an instance of a class pretty much the way you were trying to do, but with curly braces instead of parentheses:

Base b{}; // Object instantiation! (what you want, in C++11)
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • Oh, I get it now ... still I think it is very weird that I'm able to declare a function in the main function, but not to define it there. – kaspersky Mar 08 '13 at 18:39