static constants in a class

U

Urs Thuermann

How should one define a constant, say of type int, in a class? The
only way that worked for me in all cases is to delcare the constant in
the class in the header file and define its value in the
implementation file:

---- foo.hh ----
class Foo {
public:
static const int N;
...
};
---- foo.cc ----
#include "foo.hh"
const int Foo::N = 10;
----------------

But this will prevent many optimizations by the compiler, e.g. when I
compile

---- bar.cc ----
void f() {
int array[N];
for (int i = 0; i < N; i++) { ... }
----------------

since the compiler doesn't know the value of N. Is it possible to
have the constant in foo.hh, i.e. visible in all translation units
including foo.hh, without getting other problems?

I tried two other ways, both having problems:

1. class Foo {
public:
static const int N;
...
};
const int Foo::N = 10;

If I include this into multiple translation units I get multiple
definitions of N and therefore a linker error.

2. class Foo {
public:
static const int N = 10;
...
};

This seemed to work at first glance, since the compiler will
optimize most accesses to N away and use the value directly.

But when N is used where a reference is needed, e.g.

some_std_list.push_back(N);

my compiler (gcc) produces an access to N which however is not
defined anywhere so I get a linker error again.

The traditional C way would be to use #define, but I wanted to avoid
that. Is there way to have the constant definition in the header
file?

urs
 
I

Ian Collins

How should one define a constant, say of type int, in a class? The
only way that worked for me in all cases is to delcare the constant in
the class in the header file and define its value in the
implementation file:

---- foo.hh ----
class Foo {
public:
static const int N;
...
};
---- foo.cc ----
#include "foo.hh"
const int Foo::N = 10;
----------------

But this will prevent many optimizations by the compiler, e.g. when I
compile

---- bar.cc ----
void f() {
int array[N];

This shouldn't compile, C++ doesn't have VLAs (yet, and they are
optional in the new standard).
for (int i = 0; i< N; i++) { ... }

This isn't really an optimisation issue, it is unlikely the compiler
would use an immediate compare in a loop construct.
since the compiler doesn't know the value of N. Is it possible to
have the constant in foo.hh, i.e. visible in all translation units
including foo.hh, without getting other problems?

I tried two other ways, both having problems:

1. class Foo {
public:
static const int N;
...
};
const int Foo::N = 10;

If I include this into multiple translation units I get multiple
definitions of N and therefore a linker error.
Correct.

2. class Foo {
public:
static const int N = 10;
...
};

This seemed to work at first glance, since the compiler will
optimize most accesses to N away and use the value directly.

But when N is used where a reference is needed, e.g.

It will work as long as the address of N isn't required.
some_std_list.push_back(N);

my compiler (gcc) produces an access to N which however is not
defined anywhere so I get a linker error again.
Correct.

The traditional C way would be to use #define, but I wanted to avoid
that. Is there way to have the constant definition in the header
file?

Use the cleaner C way: an enum constant.

enum{ N = 10 };
 
J

Juha Nieminen

Urs Thuermann said:
How should one define a constant, say of type int, in a class?

This actually might be considered a small defect in C++. The problem
is that if you have a public static variable, even if it's const, you
must be able to get its address, and for that it must have an actual
storage, which is why you have to define it (in addition to declaring
it inside the class declaration).

The major defect with this is that such variable cannot be defined
as "inline", like functions can, except if your class is templated.
(I find it a bit odd that they effectively had to make static members
of template classes act as if they had been defined as "inline", out
of necessity, but they didn't extend this feature to non-templated
classes. Why not? It would be useful.)

You could, of course, declare it outside of the class (in which case
its constness makes it a compile-time constant and hence does not
produce those linker errors about multiple definitions), but that's a
bummer because it contaminates the global (or at least the outer)
namespace, even if you name it descriptively (such as "Foo_N" in your
example).
 
M

Marc

Urs said:
How should one define a constant, say of type int, in a class? The
only way that worked for me in all cases is to delcare the constant in
the class in the header file and define its value in the
implementation file:

---- foo.hh ----
class Foo {
public:
static const int N;
...
};
---- foo.cc ----
#include "foo.hh"
const int Foo::N = 10;
----------------

What happens if you move the "= 10" from where it is to the "static"
line, keeping all the rest unchanged?
 
I

Ian Collins

What happens if you move the "= 10" from where it is to the "static"
line, keeping all the rest unchanged?

He answered that in the part of the post you snipped....
 
A

Alain Ketterlin

Urs Thuermann said:
How should one define a constant, say of type int, in a class? The
only way that worked for me in all cases is to delcare the constant in
the class in the header file and define its value in the
implementation file:

---- foo.hh ----
class Foo {
public:
static const int N;
...
};
---- foo.cc ----
#include "foo.hh"
const int Foo::N = 10;
----------------
[...]

Make it a inline static method:

class Foo {
...
inline static int N() { return 10; }
...
};

-- Alain.
 
I

Ian Collins

Urs Thuermann said:
How should one define a constant, say of type int, in a class? The
only way that worked for me in all cases is to delcare the constant in
the class in the header file and define its value in the
implementation file:

---- foo.hh ----
class Foo {
public:
static const int N;
...
};
---- foo.cc ----
#include "foo.hh"
const int Foo::N = 10;
----------------
[...]

Make it a inline static method:

class Foo {
...
inline static int N() { return 10; }
...
};

The inline is unnecessary, but even without it the solution isn't valid:
Foo::N() isn't a compile time constant.
 
A

Alain Ketterlin

The inline is unnecessary,

Sorry for the noise, but I'm used to write down as much as I can,
especially things that are optional.
but even without it the solution isn't valid: Foo::N() isn't a compile
time constant.

It breaks arrays (unless your compiler has anticipated the new standard)
and templates (constexpr is required in that case). I can't see any
practical case where this is a problem (and if you need to take the
address of a constant int, you're really doing something weird).

BTW, in another message someone said that the compiler is unlikely to
use an immediate in a loop compare. From:

for ( int i=0 ; i<X::N() ; i++ )
printf("%d\n",i);

g++ 4.4.5 on x86-64 produced:

400720: 89 da mov %ebx,%edx
400722: be 7c 08 40 00 mov $0x40087c,%esi
400727: bf 01 00 00 00 mov $0x1,%edi
40072c: 31 c0 xor %eax,%eax
40072e: e8 75 fe ff ff callq 4005a8 <__printf_chk@plt>
400733: 83 c3 01 add $0x1,%ebx
400736: 83 fb 2a cmp $0x2a,%ebx
400739: 75 e5 jne 400720 <main+0x30>

-- Alain.
 
T

TonyO

How should one define a constant, say of type int, in a class?

<snip>

---- foo.hh ----
class Foo {
public:
static const int N = 10; // initialise here, in declaration
...
};
---- foo.cc ----
#include "foo.hh"
const int Foo::N; // single definition - no initialiser required
---- bar.cc ----
#include "foo.hh"
void f() {
int array[Foo::N]; // remember to qualify the name when used
for (int i = 0; i < Foo::N; i++) { ... }
----------------
 
M

Marc

Ian said:
He wrote

2. class Foo {
public:
static const int N = 10;
...
};

I said: "move". So in foo.h:
struct Foo {
static const int N = 10;
};

and in foo.cc:
const int Foo::N;
N can only be initialised once.

Am I initializing it several times?
 
C

Christopher

How should one define a constant, say of type int, in a class?  The
only way that worked for me in all cases is to delcare the constant in
the class in the header file and define its value in the
implementation file:
---- foo.hh ----
     class Foo {
     public:
       static const int N;
       ...
     };
---- foo.cc ----
     #include "foo.hh"
     const int Foo::N = 10;
---------------- [...]

Make it a inline static method:
     class Foo {
         ...
         inline static int N() { return 10; }
         ...
     };

The inline is unnecessary, but even without it the solution isn't valid:
Foo::N() isn't a compile time constant.


Where did the OP require it to be a _compile_ time constant? He just
said constant. The FAQ leads one to believe this is the proper way to
define a constant that is accessable outside of a class, in order to
avoid the initialization fiasco. I suppose any solution to define a
_compile_ time constant does not avoid the initialization fiasco
problem, except using #define...

I do not understand the template solution proposed, what are the
internal workings that make it advantagous?

If the constant is to not be accessable outside the class, then one
would just declare a non static const member varibale and initialize
it in the initialization list.
 
I

Ian Collins

Where did the OP require it to be a _compile_ time constant?

---- bar.cc ----
void f() {
int array[N];
for (int i = 0; i < N; i++) { ... }
----------------
I do not understand the template solution proposed, what are the
internal workings that make it advantagous?

It was unnecessarily complex.

The correct solution was the one posted by "Marc".
 
I

Ian Collins

I said: "move". So in foo.h:
struct Foo {
static const int N = 10;
};

and in foo.cc:
const int Foo::N;


Am I initializing it several times?

I misunderstood your original post.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top