2

I'm with c++11. I'm trying to initialice a multidimensional array. The first try was

const static int COORDINATES[4][4][2]={{{-1,-1},{0,0},{1,1},{2,0}},
                                       {{-1,1},{0,0},{1,-1},{0,-2}},
                                        {{1,1},{0,0},{-1,-1},{-2,0}},
                                         {{1,-1},{0,0},{-1,1},{0,2}}}; 

Compiler complained about a constexpr, so I wrote

constexpr const static int COORDINATES[4][4][2]={{{-1,-1},{0,0},{1,1},{2,0}},
                                       {{-1,1},{0,0},{1,-1},{0,-2}},
                                        {{1,1},{0,0},{-1,-1},{-2,0}},
                                         {{1,-1},{0,0},{-1,1},{0,2}}};

No erros, but when I use the array in a method, get an error. I don't understand...

void LShape::rotateShape(Square* cloneSquares) {
    int var=COORDINATES[1][1][1]; //no problems
    int x=2;
    var=COORDINATES[0][x][0]; //error 'not defined' because of x
                             //if changed to number, works
}

The error:

LShape.cpp:23: referencia a `LShape::COORDINATES' sin definir //reference to L...S not defined

Where line 23 is the second use of COORDINATES

My complete code, LShape header

#ifndef LSHAPE_H 
#define LSHAPE_H

#include "Square.h"
#include "EmptySquare.h"
#include "Shape.h"

class LShape : public Shape {

public:
LShape();
LShape(const LShape& orig);
virtual ~LShape();

inline int getState() {return state;}
inline int getNUMBER_OF_STATES() {return NUMBER_OF_STATES;}
inline int getNUMBER_OF_SQUARES() {return NUMBER_OF_SQUARES;} 

void rotateShape(Square* cloneSquares);


private:
int state;
static const int NUMBER_OF_STATES=4;
static const int NUMBER_OF_SQUARES=4;


constexpr const static int INITIAL_COORDINATES[3][2]={{1,0},{1,0},{1,1}};

constexpr const static int COORDINATES[4][4][2]={{{-1,-1},{0,0},{1,1},{2,0}},
                                       {{-1,1},{0,0},{1,-1},{0,-2}},
                                        {{1,1},{0,0},{-1,-1},{-2,0}},
                                         {{1,-1},{0,0},{-1,1},{0,2}}}; 


};
#endif  /* LSHAPE_H */

LShape code

#include "../../include/LShape.h"

LShape::LShape() : Shape(){
    //numberSquares=4;
    //squares = new Square[numberSquares];
}

LShape::~LShape(){
    //dtor
}

LShape::LShape(const LShape& other){
    //copy ctor
}


void LShape::rotateShape(Square* cloneSquares) {

    int var=COORDINATES[1][1][1]; //no problems
    int x=2;
    var=COORDINATES[0][x][0]; //error not defined
}

By the way, I'm newbie in C++, don't be bad with me :)

EDIT: I'm using the default compiler in linux (GCC) the IDE is using the following command

g++ -std=c++11   -c -g -MMD -MP -MF "build/Debug/GNU-Linux-x86/src/shape/LShape.o.d" -o build/Debug/GNU-Linux-x86/src/shape/LShape.o src/shape/LShape.cpp
  • you include shape.h before you define the coordinates ! – Christophe Aug 29 '14 at 18:01
  • @Christophe I can't see what is the problem with that... coordinates is only in LShape, not shape – Dorian Hawkmoon Aug 29 '14 at 18:05
  • @Piotr S. I'm using the default compiler in linux (GCC) the IDE is using the following command g++ -std=c++11 -c -g -MMD -MP -MF "build/Debug/GNU-Linux-x86/src/shape/LShape.o.d" -o build/Debug/GNU-Linux-x86/src/shape/LShape.o src/shape/LShape.cpp – Dorian Hawkmoon Aug 29 '14 at 18:12

2 Answers2

4

The fact that the array is a class member is an important part of this puzzle.

static constexpr (and in some cases, also const) class members have a special rule that they don't require a definition if they are never odr-used. But your program does odr-use the variable, so according to the C++ standard you need a definition.

The reason the behavior changed between 2 and x is that in the former case the optimizer was able to eliminate runtime access to the array. But you can't rely on this1, the rule is that the definition is required if there is an odr-use.

Here's the full rule, found in section 9.4.2 ([class.static.data]):

If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment- expression is a constant expression (5.19). A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. — end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.


In other circumstances, the optimization is required. For example, you could use

var = sizeof (char[COORDINATES[0][2][0]]);

which is never an odr-use of COORDINATES. But this guarantee is made only where a constant expression is required, like in an array bound, and not in general.

Of course things go wrong if you try to use a negative array bound. So maybe you'd prefer:

enum { varc = COORDINATES[0][2][0] };
var = varc;

The point is using it in a context which absolutely must be evaluated at compile time.

Community
  • 1
  • 1
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • I put constexpr const int LShape::COORDINATES[4][4][2]; at the end of header and now compile. Hope it don't give more problems, haha. Thanks for the explanation. – Dorian Hawkmoon Aug 29 '14 at 18:23
0

I removed `constexpr' and was able to compile the code at http://www.compileonline.com/compile_cpp_online.php

const static int COORDINATES[4][4][2]={{{-1,-1},{0,0},{1,1},{2,0}},
                                      {{-1,1},{0,0},{1,-1},{0,-2}},
                                      {{1,1},{0,0},{-1,-1},{-2,0}},
                                      {{1,-1},{0,0},{-1,1},{0,2}}}; 


void LShape_rotateShape() 
{

    int var=COORDINATES[1][1][1]; //no problems
    int x=2;
    var=COORDINATES[0][x][0]; //error not defined
}

I compiled it successfully with the following compilers:

  • C++ Online (GNU GCC version 4.8.1)
  • C++11 Online (GNU GCC version 4.7.2)
Andrej Adamenko
  • 1,650
  • 15
  • 31