static const variables

Discussion in 'C++' started by Philip Potter, Jul 26, 2006.

  1. 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
     
    Philip Potter, Jul 26, 2006
    #1
    1. Advertising

  2. Philip Potter wrote:
    > 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
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 26, 2006
    #2
    1. Advertising

  3. Philip Potter

    Howard Guest

    "Victor Bazarov" <> wrote in message
    news:ea803i$9cu$...
    > Philip Potter wrote:


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


    >>
    >> //jimmy.h
    >> class jimmy {
    >> public:
    >> static const int foo=5;
    >> };
    >>
    >> //jimmy.cpp
    >> #include "jimmy.h"
    >> const int jimmy::foo;
    >>



    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
     
    Howard, Jul 26, 2006
    #3
  4. 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)

    > 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
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 26, 2006
    #4
  5. Philip Potter

    Howard Guest

    "Victor Bazarov" <> wrote in message
    news:ea82qu$f6l$...
    > 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?

    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
     
    Howard, Jul 26, 2006
    #5
  6. Howard wrote:
    > "Victor Bazarov" <> wrote in message
    > news:ea82qu$f6l$...
    >> 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.

    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
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 26, 2006
    #6
  7. Philip Potter

    red floyd Guest

    Victor Bazarov wrote:
    > 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)

    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.
     
    red floyd, Jul 26, 2006
    #7
  8. 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.

    --

    Frederick Gotham
     
    Frederick Gotham, Jul 26, 2006
    #8
  9. Howard wrote:
    > ...
    > 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.

    --
    Best regards,
    Andrey Tarasevich
     
    Andrey Tarasevich, Jul 26, 2006
    #9
  10. "Victor Bazarov" <> wrote in message
    news:ea803i$9cu$...
    > Philip Potter wrote:
    > > 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.


    Thank you very much for a clear response! It seems like an ugly language
    feature. What is the ODR?

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


    Hooray!

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


    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
     
    Philip Potter, Jul 26, 2006
    #10
  11. Philip Potter

    Howard Guest

    "Andrey Tarasevich" <> wrote in message
    news:...
    > Howard wrote:
    >> ...
    >> 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.
    >
    > --
    > Best regards,
    > Andrey Tarasevich


    Thanks for the clarification, Andrey.

    -Howard
     
    Howard, Jul 26, 2006
    #11
  12. Philip Potter

    Howard Guest

    "Victor Bazarov" <> wrote in message
    news:ea84pr$imv$...
    > Howard wrote:
    >> "Victor Bazarov" <> wrote in message
    >> news:ea82qu$f6l$...
    >>> 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
     
    Howard, Jul 26, 2006
    #12
  13. Philip Potter wrote:
    > [..] What is the ODR?


    One Definition Rule.

    > [..]


    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 26, 2006
    #13
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Rakesh Sinha
    Replies:
    4
    Views:
    1,854
    Rakesh Sinha
    Jan 13, 2005
  2. Dave
    Replies:
    10
    Views:
    35,310
    Ron Natalie
    May 22, 2005
  3. Replies:
    11
    Views:
    1,109
  4. Javier
    Replies:
    2
    Views:
    571
    James Kanze
    Sep 4, 2007
  5. er
    Replies:
    3
    Views:
    386
Loading...

Share This Page