0

I am getting a strange c++ error:

main.cpp:81:9: error: request for member ‘push_back’ in ‘points’, which is of non-class type ‘std::vector<std::vector<float> >()’

I am reading this like c++ is trying to tell me that the function push_back is not part of the vector class. Here is my relevant code:

        vector<vector<float> > points(); //construct an empy vector of vectors                                          
        vector<float> first(3,0);        //construct 0 vector in R^3                                                     
        points.push_back(first);         //put (0, 0, 0) in points
  1. Where is my error here and why does c++ not like this? This seems very intuitive to me.

All help is greatly appreciated!

CodeKingPlusPlus
  • 15,383
  • 51
  • 135
  • 216
  • possible duplicate of [Default constructor with empty brackets](http://stackoverflow.com/questions/180172/default-constructor-with-empty-brackets) – Rapptz Aug 04 '13 at 20:14
  • 1
    Note that a vector of vectors is a terrible data structure for manipulating "points". The overhead of the "point" vector's dynamic allocation will be huge if you work with many points. A `class Point` or at least a `std::array` (or `std::tr1::array`) would be better. – Ben Jackson Aug 04 '13 at 20:20
  • @BenJackson If all points have the same dimension ;) – dyp Aug 04 '13 at 20:22
  • @DyP If they don't, `std::tuple` to the rescue. – Rapptz Aug 04 '13 at 20:32

1 Answers1

6

This is a case of MVP (Most Vexing Parse):

vector<vector<float> > points();

This is actually a function declaration, change it to:

vector<vector<float> > points;

With the first version, C++ thinks you're declaring a function called points which takes no arguments and returns a vector of vector of floats. That's why it's complaining about it being a non-class type.

Borgleader
  • 15,826
  • 5
  • 46
  • 62
  • Does c++ automatically the default constructor then? – CodeKingPlusPlus Aug 04 '13 at 20:13
  • 1
    Yes it will still be default constructed. [See example](https://ideone.com/8tIV1a) – Borgleader Aug 04 '13 at 20:14
  • Does the Most Vexing Parse relate to c++ having an ambiguous grammar? – CodeKingPlusPlus Aug 04 '13 at 20:15
  • I believe that's the case. – Borgleader Aug 04 '13 at 20:16
  • In C++11 you could also write `vector> points{};` (note the curly braces). – celtschk Aug 04 '13 at 20:17
  • @CodeKingPlusPlus This example has nothing to do with *ambiguous grammar* or *syntax*. The Standard clearly defines the meaning of it, but it's different to what you think. I think it's an example of context-dependence. – dyp Aug 04 '13 at 20:20
  • 1
    @DyP: Actually, the grammar itself *is* ambiguous. The standard just resolves this ambiguity by saying that everything that *can* be parsed as a function declaration *will* be parsed as such. – Xeo Aug 04 '13 at 20:23
  • @DyP The example has everything to do with ambiguous grammer. The C++ standard recognizes this, and provides additional rules outside the grammar in order to resolve such ambiguities. – James Kanze Aug 04 '13 at 20:25
  • @JamesKanze @Xeo I'm not exactly sure, but I think `()` is not a valid *initializer*. Therefore, the `()` is part of the *declarator*, and the whole thing unambiguously declares a function. (An *initializer* is a *brace-or-equal-initializer* or a `(` *expression-list* `)`, where the expr-list is *not* optional.) – dyp Aug 04 '13 at 20:46
  • @DyP Initialisers are part of the declarator, always. In a direct initialization, the name of the object being initialised is followed by a list or arguments for the constructor, in parentheses. In all other contexts, `MyType()` is legal. The only reason it isn't legal here is that there is ambiguity, and the special rules for such ambiguities resolve to something unexpected. – James Kanze Aug 04 '13 at 20:51
  • @JamesKanze I think the *initializer* is part of the *init-declarator*, not of the *declarator* itself. – dyp Aug 04 '13 at 20:53
  • Actually, it seems @DyP is right: §8.5/10 "Note: Since `()` is not permitted by the syntax for *initializer* [...]" – Xeo Aug 04 '13 at 20:55
  • BTW, in pre-C++11, would it have been possible according to the standard to get the intended parse by prefixing the definition with `auto`? Of course in C++11, it cannot work because the meaning of `auto` changed completely. – celtschk Aug 04 '13 at 21:10
  • @JamesKanze Also see [this comment](http://stackoverflow.com/questions/1424510/most-vexing-parse-why-doesnt-a-a-work#comment1268399_1424510) and the following one. – dyp Aug 04 '13 at 21:13
  • 1
    @celtschk It would see not, since as Xeo points out, the grammar for the *initializer* seems to say *expression-list*, and not *expression-list[opt]* (which is the case every where else). (It's really a technical detail, since the effect is the same.) – James Kanze Aug 04 '13 at 21:13