2

When creating a multidimensional array im getting the following error:

a non static member reference must be relative to a specific object c++

My code:

class Level
{
private:
    int width = 6;
    int height = 6;
    Room rooms[width][height];
public:
    Level();
    ~Level();
};

When width and height are replaced, when creating the array, with 6 (the value of the int's) it works. Why can't I use an int that holds the same value?

I don't need variable sizes (else I should use a vector), I thought using some variables would make it more readable for others when reading it.

In my constructor im going to fill the array in a for loop like:

Level::Level(int id)
{
    for (int i = 0; i < levelWidth; i++)
    {
        for (int x = 0; x < levelHeight; x++)
        {
          //Do the filling here
        }
    }
}
Sven van den Boogaart
  • 11,833
  • 21
  • 86
  • 169
  • You can't do this in C++. – 101010 Oct 30 '15 at 13:13
  • 1
    Maybe you intended `static const int width = 6;`. Otherwise, `width` is not an int that holds that value. `width` is a member of `Level` whose default initialization would be that value. – JSF Oct 30 '15 at 13:14
  • C-style array dimensions must be constant expressions. Use C++-style arrays if the dimensions may be different – M.M Oct 30 '15 at 13:17
  • @101010 You can't do this in any other language either. This is trying to tie the size of a two-dimensional array to two variables. – dascandy Oct 30 '15 at 13:24
  • @dascandy you can do it in C nowadays. – 101010 Oct 30 '15 at 13:29
  • @dascandy also in java it's fine, im pretty sure in c# too. I tried this code http://pastebin.com/i2YdW9tT in java. – Sven van den Boogaart Oct 30 '15 at 13:30
  • @SvenB why not make use of std::array? See my last edit. – LBes Oct 30 '15 at 13:45
  • @LBesancon I want to understand why it's not working what I intend so that i understand what is happening. In other language i always did it like that so i would really like to know why it's not working in c++ – Sven van den Boogaart Oct 30 '15 at 13:48
  • @SvenB Hope my new answer will help :) – LBes Oct 30 '15 at 13:59
  • @101010 Not as part of a class - in part due to C not having classes. Same goes for java and C# for class members. Only thing you can do is dynamically allocate it at object creation time - but then again, you can do that in C++ as well. – dascandy Oct 30 '15 at 14:53

3 Answers3

4

This is not allowed in c++. You cannot create variable size array.

If you want to have a variable size I suggest allocating your memory in the constructor according to width and height and declare room as Room** rooms;

If you really need variable length, you could also use std::vector In your case you would have: std::vector<std::vector<Room>> rooms


Edit: If you don't need variable length, in that case you need to make width and height static members or you could use std::array which explicitly made for fixed-sized arrays.


Edit2:

Reason why what you are trying to do is not working is because VLA were not implemented in C++ (they are in C though) because if you have a variable size you can simply use the std::vector. You can find some discussions here on that topic.

Also it would appear that what you want to achieve is ok if you use clang (see discussion here) even though it is contrary to the standards.

Community
  • 1
  • 1
LBes
  • 3,366
  • 1
  • 32
  • 66
4

If you have access to C++11 you can use constexpr values

class Level
{
private:
    static constexpr int width = 6;
    static constexpr int height = 6;
    Room rooms[width][height];
public:
    Level();
    ~Level();
};

Please note that both member are now static. Constexpr means that the value can be evaluated at compile time, so it's not a variable size array.

If you want variable sized array you must use vector or (not recommended) use your own memory allocation strategy.

const works, but constexpr are better. constexpr Says that the value can be evaluated at compile time, even with more complex types. You can even make them function, like

static constexpr int width() { return 6; }

And more importantly, you can use the values inside template parameters.

std::array<std::array<Room, width>, height>

If you can, I suggess you to read about std::array, because they provide a zero overhead alternative to raw arrays

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • Why constexpr and not const. const seems to work to. – Sven van den Boogaart Oct 30 '15 at 13:23
  • 1
    there is [no difference between `const` and `constexpr` for `const`literal types](http://stackoverflow.com/a/14117121/678093) – m.s. Oct 30 '15 at 13:30
  • if the type of the value changes, like `Vector2i` to contain `x` and `y`, `constexpr` will be required anyway. – Guillaume Racicot Oct 30 '15 at 13:33
  • There is absolutely no garanties about the fact that it will be evaluated at compile time. You can further refer to some posts that were made on SO: http://stackoverflow.com/questions/14116003/difference-between-constexpr-and-const. So no difference between them for this at least – LBes Oct 30 '15 at 13:33
  • 1
    garaties that not __will__ be evaluated at compile time, but __can__ be evaluated at compile time. – Guillaume Racicot Oct 30 '15 at 13:34
  • @GuillaumeRacicot you just wrote: "constexpr garanties that the value can be evaluated at compile time". Which is not true at all – LBes Oct 30 '15 at 13:35
  • @GuillaumeRacicot When using const i can use the value of levelWidth in my constructor, when using constexpr i can't. I want to use these values in my levelWidth to fill the array in a for loop. (i could use length but i was trying with the ints that have the size). – Sven van den Boogaart Oct 30 '15 at 13:35
  • 1
    @LBesancon then I really don't know what `constexpr` means if it don't mean that the expression must be valid to use at compile time. in a constant expression context, you can't do something that cannot be known at compile time, so it indeed garanties that it __can__ be evaluated at compile time. However, the expression can also be evaluated at runtime, but still need to be valid at compile time. – Guillaume Racicot Oct 30 '15 at 14:00
  • 1
    Maybe I misunderstood what you meant in your initial answer. I thought you meant that constexpr are necessarily evaluated at compile time. My bad if I misunderstood – LBes Oct 30 '15 at 14:02
1

if you need to provide dimension length you should define it as static const or in c++11 static contexpr or perhaps pass those argument as template parameters like this

template<std::size_t Width, std::size_t Height>
class Level
{
private:
    Room rooms[Width][Height];
public:
    Level();
    ~Level();
};

or even better use std::array

and if the dimension length not need you may use std::vector

MORTAL
  • 383
  • 2
  • 10