Integral const static member initialized inside a class

Discussion in 'C++' started by subramanian100in@yahoo.com, India, Jan 15, 2010.

  1. , India

    , India Guest

    In the book C++ Primer(Fourth Edition) by Stanley Lippman, the
    following is mentioned in page 471(Under the subsection "Intergral
    const static Members Are Special")

    "When a const static data member is initialized in the class body, the
    data member must still be defined outside the class definition."

    Here I understand that the data member should be of integral type. But
    I do not get compilation error even if I do not define the integral
    const static data member outside the class. Consider the following
    program named x.cpp:
    #include <cstdlib>
    #include <iostream>

    using namespace std;

    class Test
    {
    public:
    static int get(void);
    private:
    static const int x = 100;
    };

    inline int Test::get(void)
    {
    return x;
    }

    int main()
    {
    cout << Test::get() << endl;

    return EXIT_SUCCESS;
    }

    Here note that Test::x is not defined outside the class definition.

    When I compile this program with g++ 3.4.3
    g++ -std=c++98 -pedantic -Wall -Wextra x.cpp
    the program produces the following output when run:
    100

    Is it a bug in the compiler not to flag the missing definition of
    Test::x outside the class or what is mentioned in the 'C++ Primer'
    book is wrong ? Kindly clarify.
    (This question is for learning purpose only. Stroustrup has suggested
    the use of enum in such situations, in his book TC++PL Third Edition
    Page 249 - Section '10.4.6.2 Member Constants'. But he also mentions
    in this page that an initialized static integral constant member must
    still be uniquely defined somewhere and the initializer may not be
    repeated.)

    Thanks
    V.Subramanian
     
    , India, Jan 15, 2010
    #1
    1. Advertising

  2. , India wrote:
    > #include <cstdlib>
    > #include <iostream>
    >
    > using namespace std;
    >
    > class Test
    > {
    > public:
    > static int get(void);
    > private:
    > static const int x = 100;
    > };
    >
    > inline int Test::get(void)
    > {
    > return x;
    > }
    >

    ........
    > Is it a bug in the compiler not to flag the missing definition of
    > Test::x outside the class or what is mentioned in the 'C++ Primer'
    > book is wrong ? Kindly clarify.


    I think that consts of simple types are actually never defined
    in memory,rather just hard coded, unless you take address of them.
    That's why you have to define it, but it is unused if you don;t
    need pointer.

    If that is not the case then you couldn't take address of such const.


    To be honest I never took address of such const ;)

    Greets
     
    Branimir Maksimovic, Jan 15, 2010
    #2
    1. Advertising

  3. , India

    SG Guest

    On 15 Jan., 16:32, subramanian wrote:
    > In the book C++ Primer(Fourth Edition) by Stanley Lippman, the
    > following is mentioned in page 471(Under the subsection "Intergral
    > const static Members Are Special")
    >
    > "When a const static data member is initialized in the class body, the
    > data member must still be defined outside the class definition."
    >
    > Here I understand that the data member should be of integral type. But
    > I do not get compilation error even if I do not define the integral
    > const static data member outside the class.


    I think the author just wanted to make clear that even if an in-class
    initialization of a static const member is present, it is still only a
    declaration, not a definition.

    You "do not get compilation error" because the compiler is happy with
    declarations alone. If you really miss a definition for something that
    is needed the LINKER will complain about this (linker error, not
    compilation error).

    In this instance, only the value of this static const member is
    accessed. The compiler already knowns the value due to the
    initialization and the constness. It's a compile-time constant and
    doesn't require accessing the static object at runtime. If, however,
    you take the address of this member or use it as an argument for a
    function call that takes a reference-to-const you need to provide a
    definition for the member or else the LINKER will complain about
    undefined symbols.

    It's common practice in metaprogramming not to provide definitions for
    those compile-time constants.

    Cheers,
    SG
     
    SG, Jan 15, 2010
    #3
  4. Quoting the standard 9.4.2 recital 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 constant expression (5.19). 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 programm and the
    namespace scope definition shall not contain an initializer.
    **

    My interpretation is, that the following additional line is needed
    to be "standard compliant". Might be wrong. So g++ offers the service,
    that you can forget about the definition in namespace scope.

    ....

    class Test
    {
    public:
    static int get(void);
    private:
    static const int x = 100;
    };

    //pay attation to that line
    const int Test::x;

    ....

    Yours sincerely,

    Eric
     
    Eric Böse-Wolf, Jan 15, 2010
    #4
  5. , India

    James Kanze Guest

    On Jan 15, 3:32 pm, ", India"
    <> wrote:
    > In the book C++ Primer(Fourth Edition) by Stanley Lippman, the
    > following is mentioned in page 471(Under the subsection "Intergral
    > const static Members Are Special")


    > "When a const static data member is initialized in the class body, the
    > data member must still be defined outside the class definition."


    > Here I understand that the data member should be of integral type. But
    > I do not get compilation error even if I do not define the integral
    > const static data member outside the class.


    [...]
    > Here note that Test::x is not defined outside the class definition.


    > When I compile this program with g++ 3.4.3
    > g++ -std=c++98 -pedantic -Wall -Wextra x.cpp
    > the program produces the following output when run:
    > 100


    > Is it a bug in the compiler not to flag the missing definition of
    > Test::x outside the class or what is mentioned in the 'C++ Primer'
    > book is wrong ? Kindly clarify.


    In the general case, the lack of a definition is undefined behavior,
    so
    nothing the compiler does with it could be a bug. In the specific
    case
    of initialized static members of integral type, I think there are even
    special rules which say that the definition is not required if there
    is
    an immediate lvalue to rvalue conversion (which is the case in your
    code), so the code would be legal. (Try returning an int const&,
    instead of a value. That could make a difference.)

    In practice, whether I've remembered the standard correctly or not, no
    compiler will require a definition in the case of an immediate lvalue
    to
    rvalue conversion, and most won't require a definition if there is an
    lvalue to rvalue conversion in an inline function which takes a
    reference (e.g. something like std::vector<int>).

    --
    James Kanze
     
    James Kanze, Jan 16, 2010
    #5
  6. , India

    chisholm

    Joined:
    Feb 15, 2011
    Messages:
    1
    I've just stumbled into this issue. Stroustrup's book, mentioned by the OP, says: "If (and only if) you use an initialized member in a way that requires it to be stored as an object in memory, the member must be (uniquely) defined somewhere." It doesn't say what counts as that requirement. I have some code which compiles on MSVC (2008) but does not on GCC (tested with MingW 4.5.0). So evidently they disagree on what counts. My question is, who's correct? Here is the code:

    Code:
    class A
    {
    public:
      static const int N = 1;
      enum { M };
    };
    
    void f(const int& val){}
    void g(int val){}
    
    int main(int argc, const char *argv[])
    {
      f(A::N); // error on GCC, works on MSVC
      f(A::M); // works on both
      g(A::N); // works on both
      f(5); // works on both
      return 0;
    }
    
    It seems to me that since a const ref should bind to an rvalue, invoking f should not count as using A::N in a way that "requires it to be stored as an object in memory". Indeed, f(5) works fine! Any insight on this?

    Thanks
    Andy
     
    chisholm, Feb 15, 2011
    #6
    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. Mike Hewson
    Replies:
    14
    Views:
    11,893
    Micah Cowan
    Jan 7, 2005
  2. Susan Baker
    Replies:
    2
    Views:
    517
    Alf P. Steinbach
    Jul 3, 2005
  3. John Goche
    Replies:
    5
    Views:
    669
    Victor Bazarov
    Dec 8, 2006
  4. ww
    Replies:
    4
    Views:
    393
    James Kanze
    Oct 26, 2007
  5. Immortal Nephi
    Replies:
    15
    Views:
    6,419
    Bo Persson
    Jul 23, 2010
Loading...

Share This Page