static const variables

P

Philip Potter

I'm reading the comp.lang.c++ faq and, though it is incredibly clear and
lucid in many points, I am completely confused by question 29.6:

http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.6
"Here is another even more common example:

class Fred {
public:
...
private:
static const int max_ = 107;
...
};
In this example, you would need to add the line int Fred::max_; in exactly
one .cpp file, typically in Fred.cpp."

Firstly, shouldn't it say "const int Fred::max_"?
Secondly, it indicates the following code is correct (modulo the _tmain and
tchar nonsense):

//foo.cpp
#include "jimmy.h"
#include <tchar.h>

int _tmain(int argc, _TCHAR* argv[]) {
while(jimmy::foo==5);
return 0;
}

//jimmy.h
class jimmy {
public:
static const int foo=5;
};

//jimmy.cpp
#include "jimmy.h"
const int jimmy::foo;


This code fails to compile under MSVC++, with the following output:

Compiling...
foo.cpp

Linking...

foo.obj : error LNK2005: "public: static int const jimmy::foo"
(?foo@jimmy@@2HB) already defined in jimmy.obj

Is the compiler misbehaving? Or is the FAQ misleading? Or am I just
confused?

When I remove the line "const int jimmy::foo;" from jimmy.cpp it compiles
fine under MSVC++; and if I also replace _tmain() with main(), and TCHAR
with char and so on, it compiles fine with "g++ -W -Wall -ansi -pedantic
*.cpp -ofoo". If I am supposed to be defining this static variable in one
compilation unit, g++ isn't detecting this as non-standard C++.

I can't find any reference to this in TC++PL, 3rd Ed, to clarify my
confusion. I've tried checking the index under "static member" and no
mention is made of the need to define static members in exactly one
compilation unit.

What's going on? Do I have to define it or not?

Philip
 
V

Victor Bazarov

Philip said:
I'm reading the comp.lang.c++ faq and, though it is incredibly clear
and lucid in many points, I am completely confused by question 29.6:

http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.6
"Here is another even more common example:

class Fred {
public:
...
private:
static const int max_ = 107;
...
};
In this example, you would need to add the line int Fred::max_; in
exactly one .cpp file, typically in Fred.cpp."

Firstly, shouldn't it say "const int Fred::max_"?

Yes, and Marshall will hopefully notice that and correct it.
Secondly, it indicates the following code is correct (modulo the
_tmain and tchar nonsense):

//foo.cpp
#include "jimmy.h"
#include <tchar.h>

int _tmain(int argc, _TCHAR* argv[]) {
while(jimmy::foo==5);
return 0;
}

//jimmy.h
class jimmy {
public:
static const int foo=5;
};

//jimmy.cpp
#include "jimmy.h"
const int jimmy::foo;


This code fails to compile under MSVC++, with the following output:

Compiling...
foo.cpp

Linking...

foo.obj : error LNK2005: "public: static int const jimmy::foo"
(?foo@jimmy@@2HB) already defined in jimmy.obj

Is the compiler misbehaving? Or is the FAQ misleading? Or am I just
confused?

The compier is misbehaving. The Standard requires following the ODR
and the program does just that.
When I remove the line "const int jimmy::foo;" from jimmy.cpp it
compiles fine under MSVC++; and if I also replace _tmain() with
main(), and TCHAR with char and so on, it compiles fine with "g++ -W
-Wall -ansi -pedantic *.cpp -ofoo". If I am supposed to be defining
this static variable in one compilation unit, g++ isn't detecting
this as non-standard C++.

There is a proposal on the table that makes it unnecessary to define
a static integral constant *unless* its address is taken. Your program
should be valid in either case.
I can't find any reference to this in TC++PL, 3rd Ed, to clarify my
confusion. I've tried checking the index under "static member" and no
mention is made of the need to define static members in exactly one
compilation unit.

What's going on? Do I have to define it or not?

You do, as of now, to be fully standard-compliant. However, you do
not, with many implementations today, who are (in this regard) running
ahead of the standardisation process.

V
 
H

Howard

Victor Bazarov said:
Philip Potter wrote:

Yes, and Marshall will hopefully notice that and correct it.


Victor (et al): doesn't the standard require that the member be initialized
at the point of definition, not the point of declaration? Every time I've
seen or used a static const member, the initialization is in the
implementation code, not in the class definition. I thought this was a
requirement. (But hey, I've been wrong once or twice before. This morning,
in fact.)

Also, could the lack of include guards be affecting the linking here?

-Howard
 
V

Victor Bazarov

Howard said:
[..]
Victor (et al): doesn't the standard require that the member be
initialized at the point of definition, not the point of declaration?

It allows static constants of integral type to be initialised in the
class definition. (too lazy to look up the paragraph)
Every time I've seen or used a static const member, the
initialization is in the implementation code, not in the class
definition. I thought this was a requirement. (But hey, I've been
wrong once or twice before. This morning, in fact.)

Also, could the lack of include guards be affecting the linking here?

I don't think so. Double inclusion guards need to protect from multiple
definitions when including the same header in the *same* TU more than
once (usually through other headers). It's not the case here.

V
 
H

Howard

Victor Bazarov said:
Howard said:
[..]
Victor (et al): doesn't the standard require that the member be
initialized at the point of definition, not the point of declaration?

It allows static constants of integral type to be initialised in the
class definition. (too lazy to look up the paragraph)

Yes, but the post had the initialization in the class definition, and ALSO
had a definition (without initialization) in the implementation file. When
initializing in the class definition, is it ok and/or normal to also put a
definition in the implementation file?

The OP had this:

//jimmy.h
class jimmy {
public:
static const int foo=5;
};

//jimmy.cpp
#include "jimmy.h"
const int jimmy::foo;

I'm thinking either of the following would fix things:

//jimmy.h
class jimmy {
public:
static const int foo;
};

//jimmy.cpp
#include "jimmy.h"
const int jimmy::foo=5;

....or...

//jimmy.h
class jimmy {
public:
static const int foo=5;
};

//jimmy.cpp
#include "jimmy.h"

-Howard
 
V

Victor Bazarov

Howard said:
Victor Bazarov said:
Howard said:
[..]
Victor (et al): doesn't the standard require that the member be
initialized at the point of definition, not the point of
declaration?

It allows static constants of integral type to be initialised in the
class definition. (too lazy to look up the paragraph)

Yes, but the post had the initialization in the class definition, and
ALSO had a definition (without initialization) in the implementation
file. When initializing in the class definition, is it ok and/or
normal to also put a definition in the implementation file?

Not only it's OK. It's *required* by the current Standard.

Please don't make me leaf through the Standard. Get yourself a copy
and find the exact wording, and then read the archives about the new
proposal that makes it unnecessary to define the static const integral
member if it's not used as an lvalue.

V
 
R

red floyd

Victor said:
Howard said:
[..]
Victor (et al): doesn't the standard require that the member be
initialized at the point of definition, not the point of declaration?

It allows static constants of integral type to be initialised in the
class definition. (too lazy to look up the paragraph)
9.4.2/4

Just had to look that up yesterday to beat someone over the head with :)
They were trying to inline initialize a static const double.
 
F

Frederick Gotham

Philip Potter posted:
foo.obj : error LNK2005: "public: static int const jimmy::foo"
(?foo@jimmy@@2HB) already defined in jimmy.obj


Your compiler/linker/whatever is Microsoftsque.


9.4.2/4

If a static data member is of const integral or const enumeration type, its
declaration in the class definition can specify a constant-initializer which
shall be an integral constant expression. In that case, the member can appear
in integral constant expressions. The member shall still be defined in a
namespace scope if it is used in the program and the namespace scope
definition shall not contain an initializer.
 
A

Andrey Tarasevich

Howard said:
...
Yes, but the post had the initialization in the class definition, and ALSO
had a definition (without initialization) in the implementation file. When
initializing in the class definition, is it ok and/or normal to also put a
definition in the implementation file?
...

Yes, the language (as described in C++98) makes an exception for static const
members of integral and enum types - they can be supplied with an initializer in
the class definition. Note, that presence of the initializer does not turn the
declaration of such a member into a definition, meaning that the separate
definition (without an initializer) is still required. (The updated standard
made (TC1?) some updates to that specification, as Victor already mentioned.)

In other words, the user can choose where to put the initializer for static
const member of integral or enum type. One important detail here is that when
the initializer is supplied in the class definition, the const member can be
used as an integral constant expression (ICE) everywhere in the program. When
the initializer is supplied at the point of member definition, it might only be
used as an ICE in that translation unit where it is defined, and it is not an
ICE anywhere else.

The practice to put the initializer at the point of member definition was/is
popular because certain compilers refused to accept initializers in class
definition.
 
P

Philip Potter

Victor Bazarov said:
The compier is misbehaving. The Standard requires following the ODR
and the program does just that.

Thank you very much for a clear response! It seems like an ugly language
feature. What is the ODR?
There is a proposal on the table that makes it unnecessary to define
a static integral constant *unless* its address is taken. Your program
should be valid in either case.
Hooray!


You do, as of now, to be fully standard-compliant. However, you do
not, with many implementations today, who are (in this regard) running
ahead of the standardisation process.

Well, I've patched up the code by placing #ifndef _MSC_VER / #endif around
the jimmy.cpp definition line; though I wonder if it's really worth the
effort.

Philip
 
H

Howard

Andrey Tarasevich said:
Yes, the language (as described in C++98) makes an exception for static
const
members of integral and enum types - they can be supplied with an
initializer in
the class definition. Note, that presence of the initializer does not turn
the
declaration of such a member into a definition, meaning that the separate
definition (without an initializer) is still required. (The updated
standard
made (TC1?) some updates to that specification, as Victor already
mentioned.)

In other words, the user can choose where to put the initializer for
static
const member of integral or enum type. One important detail here is that
when
the initializer is supplied in the class definition, the const member can
be
used as an integral constant expression (ICE) everywhere in the program.
When
the initializer is supplied at the point of member definition, it might
only be
used as an ICE in that translation unit where it is defined, and it is not
an
ICE anywhere else.

The practice to put the initializer at the point of member definition
was/is
popular because certain compilers refused to accept initializers in class
definition.

Thanks for the clarification, Andrey.

-Howard
 
H

Howard

Victor Bazarov said:
Howard said:
Victor Bazarov said:
Howard wrote:
[..]
Victor (et al): doesn't the standard require that the member be
initialized at the point of definition, not the point of
declaration?

It allows static constants of integral type to be initialised in the
class definition. (too lazy to look up the paragraph)

Yes, but the post had the initialization in the class definition, and
ALSO had a definition (without initialization) in the implementation
file. When initializing in the class definition, is it ok and/or
normal to also put a definition in the implementation file?

Not only it's OK. It's *required* by the current Standard.

Ok, good to know.
Please don't make me leaf through the Standard. Get yourself a copy
and find the exact wording, and then read the archives about the new
proposal that makes it unnecessary to define the static const integral
member if it's not used as an lvalue.

Andrey provided a good explanation. I've tried looking at the Standard, but
it makes my head spin. I'm good at coding, but I just can't seem to
understand that kind of "legalese". Thanks anyway...

-Howard
 

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,999
Messages
2,570,243
Members
46,838
Latest member
KandiceChi

Latest Threads

Top