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
3
  • you include shape.h before you define the coordinates ! Commented Aug 29, 2014 at 18:01
  • @Christophe I can't see what is the problem with that... coordinates is only in LShape, not shape Commented Aug 29, 2014 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 Commented Aug 29, 2014 at 18:12

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

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.
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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.