-1

I need to define its size in runtime, so I need a vector. I tried the following, but I get a compiling error:

error: 'V' is not a type

#include<iostream>
#include<vector>

class graph {
private:
    int V;
    std::vector<int> row(V);
    std::vector<std::vector<int>> matrix(V,row);
public:
    graph(int v): V(v) {}
};

Is there something I am failing to understand? Is it even allowed to initialize a vector this way?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Riccardo
  • 31
  • 4

2 Answers2

3

The compiler considers these lines:

std::vector<int> row(V);
std::vector<std::vector<int>> matrix(V,row);

as member function declarations with parameters that have unknown types and omitted names.

It seems what you need is to use the constructor's member initializer list instead, like the following:

class graph {
private:
    int V;
    std::vector<std::vector<int>> matrix;
public:
    graph(int v): V(v),  matrix( v, std::vector<int>( v ) ) {}
};
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thanks a lot! i had already gathered those lines were being considered as function declarations but i had no clue how to fix that :) thank you again! – Riccardo Jul 15 '22 at 16:22
  • You just have to use `{}` there instead of `()`. – Goswin von Brederlow Jul 15 '22 at 22:05
  • @GoswinvonBrederlow Why do I have to use {} instead of ()? I do not see any reason for std::vector – Vlad from Moscow Jul 15 '22 at 22:06
  • @VladfromMoscow Because as you say `std::vector row(V);` declares a function. `std::vector row{V};` defines a variable with initialization. Although initializing the vector with a member variable that isn't even initialized won't work. For this specific case your member initializer list is the only solution. – Goswin von Brederlow Jul 15 '22 at 22:10
  • @VladfromMoscow As I see it the question has 2 parts: 1) why the used code isn't initializing member variables. 2) why the attempted initialization isn't making any sense and gives an error. – Goswin von Brederlow Jul 15 '22 at 22:16
  • @VladfromMoscow It surprised me as well but `std::vector row{V};` is perfectly fine. It initializes `row` to be a vector of size 1 containing the value of `V`. See my answer. – Goswin von Brederlow Jul 15 '22 at 22:42
  • @GoswinvonBrederlow It is undefined behavior. – Vlad from Moscow Jul 15 '22 at 22:48
  • @VladfromMoscow Why? It's equivalent to `graph(int v): V(v), matrix( V, std::vector( V ) ) {}`. See https://stackoverflow.com/questions/10720377 – Goswin von Brederlow Jul 15 '22 at 22:55
  • @GoswinvonBrederlow Consider the following program struct A { int x; std::vector v{x}; }; int main() { A a = { 100 }; std::cout << a.v.size() << '\n'; } the size of the vector does not depend on the value of V. – Vlad from Moscow Jul 15 '22 at 22:56
  • @VladfromMoscow Works as expected. You are creating a vector with 1 element `100`. You need to use `std::vector v{std::vector(x)};` if you want a vector of size `100`. Point 3 in my answer. – Goswin von Brederlow Jul 15 '22 at 23:07
  • @GoswinvonBrederlow You are right. There is a list-initialization. But he meant something another. He meant the number of elements. So this initialization as I already pointed to does not make a sense. – Vlad from Moscow Jul 15 '22 at 23:16
0

There are 3 problems with your code:

  1. You are not declaring a member variable with initialization:
    std::vector<int> row(V);
    int foo(double);

See how those two look the same. Both define a member function. Except in your case the compiler then fails to find a type definition for V and complains that V is not a type.

You have to use {} to initialize member variables inside classes:

   class Foo {
       int x{5};
   };
  1. You are using the wrong type in the initialization of the vector, which causes a problem for the matrix:
    #include<iostream>
    #include<vector>
    
    class graph {
    private:
        int V;
        std::vector<int> row{V};
        std::vector<std::vector<int>> matrix{V,row};
    public:
        graph(int v): V(v) {}
    };

    <source>:8:42: error: non-constant-expression cannot be narrowed from type 'int' to 'std::vector::size_type' (aka 'unsigned long') in initializer list [-Wc++11-narrowing]
        std::vector<std::vector<int>> matrix{V,row};
                                             ^
    <source>:8:42: note: insert an explicit cast to silence this issue
        std::vector<std::vector<int>> matrix{V,row};
                                             ^
                                             static_cast<size_type>( )
  1. You are getting the wrong constructor for the row vector.

If you change V to std::size_t, as it should be, you get another error:

<source>:7:26: error: non-constant-expression cannot be narrowed from type 'std::size_t' (aka 'unsigned long') to 'int' in initializer list [-Wc++11-narrowing]
    std::vector<int> row{V};
                         ^
<source>:7:26: note: insert an explicit cast to silence this issue
    std::vector<int> row{V};
                         ^
                         static_cast<int>( )

The problem is that std::vector<int> row{V}; is like std::vector<int> row{1, 2, 3, 4};, making a vector containing the int V as element. It does not create a vector of size V. You have to call the constructor for std::vector(std::size_t) explicitly.

So overall this gives you:

#include<iostream>
#include<vector>

class graph {
private:
    std::size_t V;
    std::vector<int> row{std::vector<int>(V)};
    std::vector<std::vector<int>> matrix{V,row};
public:
    graph(std::size_t v): V(v) {}
};

graph g(5);

https://godbolt.org/z/qrobf9cGq

Goswin von Brederlow
  • 11,875
  • 2
  • 24
  • 42