static constants in a class

Discussion in 'C++' started by Urs Thuermann, Sep 14, 2011.

  1. 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
    Urs Thuermann, Sep 14, 2011
    #1
    1. Advertising

  2. Urs Thuermann

    Ian Collins Guest

    On 09/15/11 09:43 AM, Urs Thuermann wrote:
    > 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 };

    --
    Ian Collins
    Ian Collins, Sep 14, 2011
    #2
    1. Advertising

  3. Urs Thuermann <> wrote:
    > 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).
    Juha Nieminen, Sep 15, 2011
    #3
  4. Urs Thuermann

    Marc Guest

    Urs Thuermann wrote:

    > 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?
    Marc, Sep 15, 2011
    #4
  5. Urs Thuermann

    Ian Collins Guest

    On 09/15/11 07:59 PM, Marc wrote:
    > Urs Thuermann wrote:
    >
    >> 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?


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

    --
    Ian Collins
    Ian Collins, Sep 15, 2011
    #5
  6. Urs Thuermann

    Marc Guest

    Ian Collins wrote:

    > On 09/15/11 07:59 PM, Marc wrote:
    >> 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....


    No, he had removed the declaration in foo.cc.
    Marc, Sep 15, 2011
    #6
  7. Urs Thuermann <> writes:

    > 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.
    Alain Ketterlin, Sep 15, 2011
    #7
  8. Urs Thuermann

    Ian Collins Guest

    On 09/15/11 08:50 PM, Alain Ketterlin wrote:
    > Urs Thuermann<> writes:
    >
    >> 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.

    --
    Ian Collins
    Ian Collins, Sep 15, 2011
    #8
  9. Urs Thuermann

    Ian Collins Guest

    On 09/15/11 08:11 PM, Marc wrote:
    > Ian Collins wrote:
    >
    >> On 09/15/11 07:59 PM, Marc wrote:
    >>> 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....

    >
    > No, he had removed the declaration in foo.cc.


    He wrote

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

    N can only be initialised once.

    --
    Ian Collins
    Ian Collins, Sep 15, 2011
    #9
  10. Ian Collins <> writes:

    > On 09/15/11 08:50 PM, Alain Ketterlin wrote:
    >> Urs Thuermann<> writes:


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


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


    > 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.
    Alain Ketterlin, Sep 15, 2011
    #10
  11. Urs Thuermann

    TonyO Guest

    On Sep 14, 10:43 pm, Urs Thuermann <> wrote:
    > 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++) { ... }
    ----------------
    TonyO, Sep 15, 2011
    #11
  12. Urs Thuermann

    Marc Guest

    Ian Collins wrote:

    > On 09/15/11 08:11 PM, Marc wrote:
    >> Ian Collins wrote:
    >>
    >>> On 09/15/11 07:59 PM, Marc wrote:
    >>>> 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....

    >>
    >> No, he had removed the declaration in foo.cc.

    >
    > 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?
    Marc, Sep 15, 2011
    #12
  13. Urs Thuermann

    Christopher Guest

    On Sep 15, 4:17 am, Ian Collins <> wrote:
    > On 09/15/11 08:50 PM, Alain Ketterlin wrote:
    >
    >
    >
    >
    >
    > > Urs Thuermann<>  writes:

    >
    > >> 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.
    >
    > --
    > Ian Collins- Hide quoted text -
    >
    > - Show quoted text -



    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.
    Christopher, Sep 15, 2011
    #13
  14. Urs Thuermann

    Ian Collins Guest

    On 09/16/11 09:24 AM, Christopher wrote:
    > On Sep 15, 4:17 am, Ian Collins<> wrote:
    >> On 09/15/11 08:50 PM, Alain Ketterlin wrote:
    >>> Urs Thuermann<> writes:

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


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

    --
    Ian Collins
    Ian Collins, Sep 15, 2011
    #14
  15. Urs Thuermann

    Ian Collins Guest

    On 09/16/11 02:03 AM, Marc wrote:
    > Ian Collins wrote:
    >
    >> On 09/15/11 08:11 PM, Marc wrote:
    >>> Ian Collins wrote:
    >>>
    >>>> On 09/15/11 07:59 PM, Marc wrote:
    >>>>> 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....
    >>>
    >>> No, he had removed the declaration in foo.cc.

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


    I misunderstood your original post.

    --
    Ian Collins
    Ian Collins, Sep 15, 2011
    #15
  16. Urs Thuermann

    Marc Guest

    Ian Collins wrote:

    > I misunderstood your original post.


    That'll teach me to try and save time by not writing 2 lines ;-)
    Marc, Sep 16, 2011
    #16
    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. Collin VanDyck
    Replies:
    8
    Views:
    800
    John C. Bollinger
    Oct 22, 2003
  2. SaravanaKumar
    Replies:
    6
    Views:
    9,358
    Tony Morris
    Oct 19, 2004
  3. John David Ratliff

    static constants...

    John David Ratliff, Nov 7, 2003, in forum: C++
    Replies:
    1
    Views:
    387
    Gianni Mariani
    Nov 7, 2003
  4. bugbear
    Replies:
    4
    Views:
    421
    bugbear
    Aug 23, 2006
  5. Robin
    Replies:
    0
    Views:
    404
    Robin
    Jun 6, 2007
Loading...

Share This Page