10

I'm new with c++ and came across to this problem. Here is my code:

class A
{
    std::vector <int> vec(10);
};

It gives me error saying expected a type specifier. I know that this way of initializing a vector is not acceptable and it should be done in constructor but I'm curious why this fails. I also noticed that this:

class A
{
    std::vector <int> vec = std::vector<int>(10);
};

Works perfectly fine.

So my question is why does second case work even though we are still creating vector with "predefined size"(std::vector<int>(10)), and why does the first case fail? thanks.

P.S I'm trying to create vector with size for 10 ints, not create a vector with with 10 already inserted in it.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
user3503143
  • 381
  • 3
  • 10
  • 4
    This is because first snippet declares a function called `vec`, which returns `std::vector` and takes a parameter of . I suppose this is the duplicate, but maybe there are better: [My attempt at value initialization is interpreted as a function declaration, and why doesn't A a(()); solve it?](https://stackoverflow.com/questions/1424510/my-attempt-at-value-initialization-is-interpreted-as-a-function-declaration-and) – Yksisarvinen Feb 08 '19 at 10:55
  • 2
    C++11 or above? use `{20}` instead of `(20)`. You declared a function which takes a syntax error and returns a `std::vector`. – mch Feb 08 '19 at 10:55
  • Thanks you for you reply. I was trying to create a vector with allocated memory for 6 members, will `{20}` do the same? – user3503143 Feb 08 '19 at 10:57
  • 1
    This is not a most vexing parse error. This is a variable definition, but in a place it is not allowed. – YSC Feb 08 '19 at 10:58
  • 2
    @mch For `vector`, as it has initializer_list constructor so they are not same. `vector(20)` : 20 elements with value of 0. `vector{20}` : just one elemnt with value of 20. – Hanjoung Lee Feb 08 '19 at 11:04
  • @Yksisarvinen No it's not. A function declaration cannot have an integer literal in place of its argument list. – rubenvb Feb 08 '19 at 13:06

3 Answers3

12

What?

Since C++11 we have non-static data member initialisers, making this approach to initialising members completely valid. However, you must use either = or {}.

Formally, if an initializer is present here, it must be with a brace-or-equal-initializer grammatical production.

Since you've instead used a syntax that doesn't count as initialisation here, the compiler tries to make a function declaration out of vec, which breaks because 20 is not a type.


Why?

The chapter named "Problem 1" in the original feature proposal (N2756) explains that () was disallowed here to avoid some confusion with respect to member function declarations.

The author does note therein that the committee could have let it be, and had it work like other declarations — that is, it's a function if it can be, and an object otherwise*. But the author decided to go a different direction and just ban the syntax to avoid the problem in this particular case.

Unfortunately, this makes initializers of the “( expression-list )” form ambiguous at the time that the declaration is being parsed [..]

One possible solution is to rely on the existing rule that, if a declaration could be an object or a function, then it’s a function [..]

A similar solution would be to apply another existing rule, currently used only in templates, that if T could be a type or something else, then it’s something else; and we can use “typename” if we really mean a type [..]

Both of those solutions introduce subtleties that are likely to be misunderstood by many users (as evidenced by the many questions on comp.lang.c++ about why “int i();” at block scope doesn’t declare a default-initialized int).

The solution proposed in this paper is to allow only initializers of the “= initializer-clause” and “{ initializer-list }” forms. That solves the ambiguity problem in most cases.

Such is life.


So?

I'm trying to create vector with size for 10 ints, not create a vector with with 10 already inserted in it.

This is an important point. Be careful, because initialising a vector with {} won't do that. "Uniform" initialisation unfortunately merely added more meanings. So much for solving the ambiguity problem…

You should therefore use either the = syntax, or just do this in the constructor (my favourite).


* This is where the most vexing parse can sometimes bite you, though not every occurrence of unintended function declarations is an example of the most vexing parse.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

It's not well written. You can use the following example as well. Here, i'll leave the vector empty, but reserve() space for 20 pointers, so you can insert without having to reallocate. A more simple and better solution (with a constructor) would be:

A.cpp

#include "A.hpp"

A::A()
{
   this->vec.reserve(20);
   std::cout << "Setting size" << std::endl;
}
A::~A()
{
}

A.hpp

#ifndef A_HPP
#define A_HPP_

#include <iostream>
#include <vector>

class A {
public:
        A();
        ~A();
        std::vector<int> vec;
};

#endif /* !A_HPP_ */

main.cpp

#include "A.hpp"

int main()
{
   A a;
}

Output:

Setting size

And your vector size is done.

mch
  • 9,424
  • 2
  • 28
  • 42
josemartindev
  • 1,413
  • 9
  • 17
0

You're not allowed to declare and initialize a member variable with the syntax type name(value);, but you can with type name{value}; or type name = value;.

This is the syntax from the Standard:

[class.mem]/1

member-declaration:
  attribute-specifier-seq(opt) decl-specifier-seq(opt) member-declarator-list(opt);
  [...]
member-declarator-list:
  member-declarator
  member-declarator-list , member-declarator
member-declarator:
  [...]
  declarator brace-or-equal-initializer(opt)
  [...]

And

[dcl.init]/1

brace-or-equal-initializer:
  = initializer-clause
  braced-init-list
braced-init-list:
  { initializer-list , (opt) }
  { designated-initializer-list , (opt) }
  { }

So the following:

class C
{
    int a = 0;
    int b{0};
}

is valid.

The definition of C::a is a member-declaration with a member-declarator-list composed of a single member initialized with a brace-or-equal-initializer of the form = initializer-clause.

Similarly, C::b uses the form braced-init-list.

On the other hand, you'll find no syntax for int c(0);.

Community
  • 1
  • 1
YSC
  • 38,212
  • 9
  • 96
  • 149