3

I want to initialize a 2D array in the constructor of a class but the compiler gives me this error "call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type".

class Matrix
{

public:
    Matrix() {};
    Matrix(size_t x, size_t y) { a(x, vector<int>(y , 0 )); }
private:
    vector<vector<int>> a; 


};
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • The right syntax for member initialization is a constructor initialization list. – SergeyA Jun 11 '19 at 14:48
  • 1
    To implement a matrix I would suggest using a 1D array. You only need a one dimensional memory layout to implement a matrix. Then, the `operator[]` would access the right element with 2D coordinates, mapped into the 1D vector. – Guillaume Racicot Jun 11 '19 at 14:50
  • 1
    Read this: [What is this weird colon-member (“ : ”) syntax in the constructor?](https://stackoverflow.com/questions/1711990/what-is-this-weird-colon-member-syntax-in-the-constructor). – WhozCraig Jun 11 '19 at 14:53

3 Answers3

6

Firstly, as mentioned, this:

Matrix(size_t x, size_t y)
{
   a(x, vector<int>(y , 0 ));
}

is not how you initialise a member. To initialise a member, we use the member initializer list, like so:

Matrix(size_t x, size_t y)
   : a(x, vector<int>(y , 0 ))
{}

The colonic syntax is a specific place for listing initialisations. Nothing in the constructor body is an initialisation. When you don't put an initialiser for a member, it is default-initialised. Then the code in your constructor's body is run. As we know, the body of a function consists of statements that are executed.

Now, when you perform the statement <name>(<thing>, <other thing>), that is a function call. If <name> is not a function but a class instance, then the function call operator operator() is looked up instead. If there isn't one (or it doesn't match the arguments), then compilation fails in the way that you've observed.

Could the language have been designed so that any mention of a member, inside the constructor body, in this form, were treated as an initialisation? Probably. But why? Now you'd have no unambiguous way to perform function-calls instead, and the order in which things happen during construction would be unclear. It's much better the way it is now.

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

Correct syntax is using initializer list:

Matrix(size_t x, size_t y) :a(x, vector<int>(y , 0 )) { }

Quimby
  • 17,735
  • 4
  • 35
  • 55
  • that's a typo? why? why i can't initialize it like i did in my code? –  Jun 11 '19 at 14:50
  • 1
    @SergeyA At this level of pickiness, it is called the _member initializer list_. Also, you should not use code formatting for not-code: it is toxic to screen readers (and, by extension, to people using them). – Lightness Races in Orbit Jun 11 '19 at 14:50
  • @ArisKoutsoukis Because that's not the way to initialise things. – Lightness Races in Orbit Jun 11 '19 at 14:51
  • 1
    @ArisKoutsoukis *"why can't I initialize it like I did in my code?"* - did it *work* ? Isn't the reason you're posting your question because it *didn't* work? – WhozCraig Jun 11 '19 at 14:52
  • @ArisKoutsoukis Because... that's the way it is? Same reason you can't fly on a bike. You just can't. Why do you think you should be able to? The code you wrote means something completely different. – Lightness Races in Orbit Jun 11 '19 at 14:54
  • @WhozCraig yes but i want to know why id doesn't work like that. –  Jun 11 '19 at 14:54
  • 1
    @ArisKoutsoukis "Because standard says so" is the reason. Body of the constructor behaves like any other function, so `a(x, vector(y , 0 ));` means a call to method called `a`. Only the initializer list is special, constructor body cannot do anything that any other member function cannot do. – Yksisarvinen Jun 11 '19 at 14:56
2

When the control is passed to the body of the constructor then the vector is already created.

So this statement

a(x, vector<int>(y , 0 ));

is not a call of a vector constructor. The vector was already created using the default constructor and the statement above is invalid.

You could use a mem-initializer list in the constructor

class Matrix
{
public:
    Matrix() {};
    Matrix(size_t x, size_t y) : a(x, vector<int>(y ) ) {}
private:
    vector<vector<int>> a; 
};

Or you could use the member function assign in the body of the constructor

class Matrix
{

public:
    Matrix() {};
    Matrix(size_t x, size_t y) { a.assign (x, vector<int>(y ) ); }
private:
    vector<vector<int>> a; 
};
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335