tags:

views:

270

answers:

3

I'm running into some compiler errors I don't understand. I'm pretty sure I'm doing something very wrong here but I don't know what. I would like all the world constants to be defined as belonging to the class.

Notes:

I'm only using classes as structs with attached members. I'm not following strict Object-Orriented Design on purpose. Please do not comment the public variables.

I'm not concerned very much about the compiler inlining stuff. I'm using this structure because it's easy for me to use. (If it worked)

class Board{
public:
    enum PhysicsResult{ BOUNCE, OUT_OF_BOUNDS_TOP, OUT_OF_BOUNDS_BOTTOM, CONTINUE };
    //World constants
    const static float Height = 500;
    const static float Width = 300;
    //ERROR: 'Board::Width' cannot appear in a constant-expression.
    const static float PaddleWidth = Width/15; 
    const static float BallRadius = 5;
    const static float BounceDistance = 1.5;
    //World Objects
    Ball ball;
    Paddle paddle1;
    Paddle paddle2;
    /*
     1---2
     |   |
     0---3
     */
    //ERROR: a brace-enclosed initalizer is not allowed here before '{' token
    //ERROR: invalid in-class initalization of static data member of nonintegral type 'const Pair[4]'
    const static Pair corners[4] = {Pair(0, 0), Pair(0, Height), Pair(Width, Height), Pair(Width, 0)};

    //ERROR: a brace-enclosed initalizer is not allowed here before '{' token
    //ERROR: invalid in-class initalization of static data member of nonintegral type 'const Pair[2]'
    const static Pair left_wall[2]   = {corners[0], corners[1]};

    //ERROR: a brace-enclosed initalizer is not allowed here before '{' token
    //ERROR: invalid in-class initalization of static data member of nonintegral type 'const Pair[2]'
    const static Pair right_wall[2]  = {corners[3], corners[2]};

    //ERROR: a brace-enclosed initalizer is not allowed here before '{' token
    //ERROR: invalid in-class initalization of static data member of nonintegral type 'const Pair[2]'
    const static Pair top_wall[2]    = {corners[1], corners[2]};

    //ERROR: a brace-enclosed initalizer is not allowed here before '{' token
    //ERROR: invalid in-class initalization of static data member of nonintegral type 'const Pair[2]'
    const static Pair bottom_wall[2] = {corners[0], corners[3]};

If it is possible to do this, what is the proper syntax for doing this? If this is not possible, what alternative should I use?

+2  A: 

You must initialize const members in the constructor initialization list.

class blah
{
    public:
            blah() : _constant( 1 ) { }

    private:
            const int _constant;
};
Martin Beckett
What is a "constructor initialization list"?
epochwolf
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.6Initializer lists are how you invoke constructors on members. In the above example it's the ": _constant(1)" part. If you need more than one, separate them with commas. i.e. blah() : _constant(1), _constant1(2), _constant2(3) {}, etc...
Eclipse
@mgb: Unfortunately, there is no way to use initializer lists to intialize static data. Also, starting identifiers with an underscore is generally bad practice. I think in this case it's ok, since it's followed by a lower case letter, but it's still not the best practice, especially in an example for someone new to C++. See http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier
Eclipse
This fails with const static variables.
epochwolf
+5  A: 

Defining the static consts outside of the body of the class compiles and executes with gcc.

#include <iostream>
using namespace std;

struct Pair { int a; int b; Pair(int x, int y) : a(x),b(y) {}};
struct F {
  static const float blah = 200.0;
  static const Pair corners[4];
};

// square boards are so ordinary
const Pair F::corners[4] = { Pair(0,0), Pair(0,1), Pair(2,0), Pair(2,2) };

const float F::blah ;

int main(int, char **) {
  cout << F::corners[0].a << endl ;
  cout << F::blah << endl;
  return 0;
}

I cannot overemphasize the importance of ebo's comment about order of initialization.

Thomas L Holaday
You will probably need to address the [static initialization order problem][1] [1]: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.13
ebo
As long as you put them in the same file, they will be initialized in order.
Eclipse
My concern would be that the Board will be in one file (board.cpp), the board users will be in another file (game.cpp), there will be static members of Game that refer to Board's corners, and that depending on what order board.obj and game.obj are linked, the program will either run or crash mysteriously.
Thomas L Holaday
if you absolutely have to access F::corners from other translation units, you can also get rid of the Pair constructor, and initialize like const Pair F::corners[4] = { { 0, 0 }, { 0, 1 }, ..... }; the objects will be initialized before any other initializations takes place directly after zero initialization of everything (static initialization. important is that all the initializer expressions must be constant expressions, and the array is a POD type). You can then access it safely from code initialized at runtime much later (dynamic initialization)
Johannes Schaub - litb
Thomas: Not a problem for my application. Paddle, Board, and Ball are the only "objects" in the code. Everything else is in global functions. I'm using OpenGL for the graphics of the program so I'm skipping OOP for this project.
epochwolf
+1  A: 

Static members of C++ objects need to be defined outside of the declaration. This is because the compiler doesn't know which translation unit (.o file) to put the members in.

Usually I will define them in the .cpp file of the implementation. You don't generally want to put them into the header file because they will end up in multiple .o files, and it will generate compiler errors because the same thing is defined multiple times.

jamuraa
Good to know for the future. I'm putting all of the code in the header at this point.
epochwolf