views:

1175

answers:

9

Hi,

I am working on a game and have an interesting question. I have some game-wide constant values that I want to implement in one file. Right now I have something like this:

constants.cpp

extern const int BEGINNING_HEALTH = 10;
extern const int BEGINNING_MANA = 5;

constants.hpp

extern const int BEGINNING_HEALTH;
extern const int BEGINNING_MANA;

And then files just #include "constants.hpp" This was working great, until I needed to use one of the constants as a template parameter, because externally-linked constants are not valid template parameters. So my question is, what is the best way to implement these constants? I am afraid that simply putting the constants in a header file will cause them to be defined in each translation unit. And I don't want to use macros.

Thanks

+8  A: 

How about enums?

constants.hpp

  enum {
    BEGINNING_HEALTH = 10,
    BEGINNING_MANA = 5
  }
Tommy Hui
A: 

perhaps something along the lines of a static class?

class CONSTANTS {
public:
static inline int getMana() { return 10;};
};
MighMoS
That doesn't help. Function values cannot be used as template parameters. C++0x keyword `constexpr` is supposed to work around that.Besides, C++ has namespaces, which are superioer to a static class for "namespacing" constants.
Tom
*superior*... I lack basic proofreading skills :)
Tom
+13  A: 

Get rid of the extern and you're set.

This code works perfectly fine in a header, because everything is "truly constant" and therefore has internal linkage:

const int BEGINNING_HEALTH = 10;
const int BEGINNING_MANA = 5;
const char BEGINNING_NAME[] = "Fred";
const char *const BEGINNING_NAME2 = "Barney";

This code cannot safely be put in a header file because each line has external linkage (either explicitly or because of not being truly constant):

extern const int BEGINNING_HEALTH = 10;
extern const int BEGINNING_MANA = 5;
const char *BEGINNING_NAME = "Wilma";  // the characters are const, but the pointer isn't
Tom
i suspect a copy/paste bug in last BEGINNING_NAME[] one. did you want to write it as BEGINNING_NAME ?
Johannes Schaub - litb
you are correct, fixed. Thanks.
Tom
You need "static", otherwise you do not get internal linkage or, more ideally, the equivalent of a "#define" with the values inlined.
Jim Buck
@Jim Buck constants in C++ have internal linkage - no need for "static"
anon
A: 

Most compilers simply don't allocate space for const POD values. They optimize them out and treat them as if they had been #defined, don't they?

greyfade
Close, but still not quite the same. Example where macros work but constants don't: #define FOO "foo"; \ const char *str = "bar" FOO; C and C++ allow concatenation of string literal tokens, but not string constants.
Tom
This is only true for integral constants. Floats, doubles, char*s, and other types will be allocated storage if optimization is disabled.
Adam Rosenfield
@Tom: That's not what I meant. I meant for POD constants, not preprocessor majicks. I meant in the sense that the symbol and the space for the value don't exist unless you attempt to take its address.
greyfade
I think POD officially includes floats and doubles, but floats and doubles are generally not optimized in this way.
Max Lybbert
A: 

As a quick answer to the title question, a singleton pattern is a possible best, C++ way to define cross-file constants and insure only one instance of the object.

As far as the template parameter problem, you need to pass a type not a value. Your type is "int".

jeffD
This seems like overkill for a set of simple constants, and is not likely to solve his problems with template instantiation.
Eclipse
Why wouldn't is solve his problem with template instantiation, since it wouldn't be an extern, it would be a local. Overkill is relative, what is the quality perspective $100M, $100K, or $100 game budget?
jeffD
jeffD, the problem is that your answer does not make sense. do you want to make an "int" a singleton? an int is comprised by value, not by identity. another thing that probably made people downvote you is that he doesn't want to pass a type, but a value to his template. Why do you say he can't?
Johannes Schaub - litb
The title to the question is a good question by itself. Maybe I do need to see more of his code. See http://www.cplusplus.com/doc/tutorial/templates.html for a ref. "A template parameter is a special kind of parameter that can be used to pass a type as argument". Wish comments allowed hyperlinks.
jeffD
Nice, the http address automatically becomes hyperized.
jeffD
jeffD, unfortunately, the tutorial at cplusplus.com isn't quite good - too incomplete and sometimes wrong. for example template declarations are not "expressions" as they say, they are declarations. blurs out the difference between a specialization and an explicit specialization on their page too.
Johannes Schaub - litb
better get a good book (there are some good threads on SO about C++ books) rather than relying on cplusplus.com . even for a reference, it has some quite blatantly wrong pages (i wonder whether they still maintain them?). and please read the very end on that linked page (about non-type parameters).
Johannes Schaub - litb
For the record, you can pass integral values to templates (Boost.Array uses this ability, I believe).
Max Lybbert
jeffD,I have a Matrix class that is uses a static array. Its class signature is template <typename T, int Rows, int Columns> class Matrix.This is perfectly legal C++ code.
rlbond
I stand by my answer to the title question. You may be right about what he's doing w/ templates, w/o seeing the code and error it's unsure. There are really two questions here, I think I'll pose one as a seperate question.
jeffD
+5  A: 

Use "static const int" in your .hpp file, and put nothing in the .cpp file (except whatever other code you have there of course).

Jim Buck
A: 

What ever happened to a simple:

#define BEGINNING_HEALTH 10

Man, those were the days.
Oh wait, those still are the days!

slacy
That might not do what you're expecting in the context of template parameters... :) rlbond needs that.
Mihai Limbășan
Some of us like our debuggers to show 'BEGINNING_HEALTH' instead of '10'.
Joe Gauterin
<sarcastic> When needs debuggers when you have printf()? </sarcastic>
slacy
+1  A: 

make use of namespaces:

namespace GameBeginning {
    const int HEALTH = 10;
    const int MANA   = 5; 
};

then u can use as player.health = GameBeginning::HEALTH;

A: 

Best to cross file is to look on nk!

ashley