the c++ standard on static constants

Discussion in 'C++' started by John Ratliff, Oct 16, 2005.

  1. John Ratliff

    John Ratliff Guest

    I'm trying to find out whether g++ has a bug or not. Wait, don't leave,
    it's a standard C++ question, I promise.

    This program will compile and link fine under mingw/g++ 3.4.2, but fails
    to link under Linux/g++ 3.3.3.

    ---------------------------------------------
    #include <iostream>
    #include <utility>

    class foo {
    private:
    char sram[0x2000];

    public:
    static const int A = 0x8;
    static const int B = 0x1FF8;

    foo() {
    sram[8] = 1;
    sram[9] = 2;
    sram[0x1FF8] = 3;
    sram[0x1FF9] = 4;
    }

    std::pair<unsigned char, unsigned char> method(bool redundant) const {
    int offset = (redundant ? B : A);

    return std::pair<unsigned char,
    unsigned char>(sram[offset], sram[offset + 1]);
    }
    };

    int main(int, char **) {
    foo f;
    std::pair<unsigned char, unsigned char> p1(f.method(false));
    std::pair<unsigned char, unsigned char> p2(f.method(true));

    std::cout << "p1 = (" << (int)p1.first << ","
    << (int)p1.second << ")\n";
    std::cout << "p2 = (" << (int)p2.first << ","
    << (int)p2.second << ")\n";

    return 0;
    }
    ---------------------------------------------

    The reason is that in mingw/g++ 3.4.2, the static constants A and B are
    replaced during compile time and didn't need storage space. The linker
    therefore didn't need to find them. However, Linux/g++ 3.3.3 generates
    code that requires them to have storage space.

    Am I supposed to declare storage space for these constants, or is it
    legal here to assume they will become compile-time constnats? What does
    the C++ standard say?

    Thanks,

    --John Ratliff
     
    John Ratliff, Oct 16, 2005
    #1
    1. Advertising

  2. John Ratliff wrote:
    > I'm trying to find out whether g++ has a bug or not. Wait, don't
    > leave, it's a standard C++ question, I promise.
    >
    > This program will compile and link fine under mingw/g++ 3.4.2, but
    > fails to link under Linux/g++ 3.3.3.
    >
    > ---------------------------------------------
    > #include <iostream>
    > #include <utility>
    >
    > class foo {
    > private:
    > char sram[0x2000];
    >
    > public:
    > static const int A = 0x8;
    > static const int B = 0x1FF8;
    >
    > foo() {
    > sram[8] = 1;
    > sram[9] = 2;
    > sram[0x1FF8] = 3;
    > sram[0x1FF9] = 4;
    > }
    >
    > std::pair<unsigned char, unsigned char> method(bool redundant)
    > const { int offset = (redundant ? B : A);
    >
    > return std::pair<unsigned char,
    > unsigned char>(sram[offset], sram[offset +
    > 1]); }
    > };
    >
    > int main(int, char **) {
    > foo f;
    > std::pair<unsigned char, unsigned char> p1(f.method(false));
    > std::pair<unsigned char, unsigned char> p2(f.method(true));
    >
    > std::cout << "p1 = (" << (int)p1.first << ","
    > << (int)p1.second << ")\n";
    > std::cout << "p2 = (" << (int)p2.first << ","
    > << (int)p2.second << ")\n";
    >
    > return 0;
    > }
    > ---------------------------------------------


    The program is well-formed. 'A' and 'B' are never used outside of
    the class definition, so they don't need to be defined. That's what
    1998 version of the Standard used to say. It was changed a bit in the
    2003 version (IIRC) but to give programmers even more leeway.

    > The reason is that in mingw/g++ 3.4.2, the static constants A and B
    > are replaced during compile time and didn't need storage space. The
    > linker therefore didn't need to find them. However, Linux/g++ 3.3.3
    > generates code that requires them to have storage space.


    In what way? Can you figure what is trying to refer to them?

    > Am I supposed to declare storage space for these constants, or is it
    > legal here to assume they will become compile-time constnats? What
    > does the C++ standard say?


    Since their address is never taken, the 'foo::A' and 'foo::B' are, in
    fact, compile-time constant expressions that do not require storage.
    The objects, therefore, don't need to be defined outside of the class
    definition. g++ 3.3.3 is probably too old. It's even too old and non-
    compliant in this particular case even with 1998 version of the C++
    Standard. The standard was amended to allow const statics to be only
    defined in the class definition if their address is not taken _even_
    if they are "used" outside the class. [I am too lazy, though, to look
    it up in the Standard...]

    V
     
    Victor Bazarov, Oct 16, 2005
    #2
    1. Advertising

  3. John Ratliff

    John Ratliff Guest

    Victor Bazarov wrote:
    > John Ratliff wrote:
    >
    >>I'm trying to find out whether g++ has a bug or not. Wait, don't
    >>leave, it's a standard C++ question, I promise.
    >>
    >>This program will compile and link fine under mingw/g++ 3.4.2, but
    >>fails to link under Linux/g++ 3.3.3.
    >>
    >>---------------------------------------------
    >>#include <iostream>
    >>#include <utility>
    >>
    >>class foo {
    >>private:
    >> char sram[0x2000];
    >>
    >>public:
    >> static const int A = 0x8;
    >> static const int B = 0x1FF8;
    >>
    >> foo() {
    >> sram[8] = 1;
    >> sram[9] = 2;
    >> sram[0x1FF8] = 3;
    >> sram[0x1FF9] = 4;
    >> }
    >>
    >> std::pair<unsigned char, unsigned char> method(bool redundant)
    >> const { int offset = (redundant ? B : A);
    >>
    >> return std::pair<unsigned char,
    >> unsigned char>(sram[offset], sram[offset +
    >> 1]); }
    >>};
    >>
    >>int main(int, char **) {
    >> foo f;
    >> std::pair<unsigned char, unsigned char> p1(f.method(false));
    >> std::pair<unsigned char, unsigned char> p2(f.method(true));
    >>
    >> std::cout << "p1 = (" << (int)p1.first << ","
    >> << (int)p1.second << ")\n";
    >> std::cout << "p2 = (" << (int)p2.first << ","
    >> << (int)p2.second << ")\n";
    >>
    >> return 0;
    >>}
    >>---------------------------------------------

    >
    >
    > The program is well-formed. 'A' and 'B' are never used outside of
    > the class definition, so they don't need to be defined. That's what
    > 1998 version of the Standard used to say. It was changed a bit in the
    > 2003 version (IIRC) but to give programmers even more leeway.
    >
    >
    >>The reason is that in mingw/g++ 3.4.2, the static constants A and B
    >>are replaced during compile time and didn't need storage space. The
    >>linker therefore didn't need to find them. However, Linux/g++ 3.3.3
    >>generates code that requires them to have storage space.

    >
    >
    > In what way? Can you figure what is trying to refer to them?


    This is the assembly generated from Linux/g++ 3.3.3 for foo::method when
    using g++ -S temp.cc. No extra optimization declared, though it doesn't
    fix it if you do -O2. The really stupid thing is that if you replace the
    ternary operator with an if statement, it will treat A and B as
    compile-time constants properly.

    -----------------------------------------------------
    _ZNK3foo6methodEb:
    ..LFB1535:
    pushl %ebp
    ..LCFI14:
    movl %esp, %ebp
    ..LCFI15:
    subl $24, %esp
    ..LCFI16:
    movl 16(%ebp), %eax
    movb %al, -1(%ebp) ; stick redundant on the stack
    cmpb $0, -1(%ebp) ; if redundant is false
    je .L6 ; goto .L6
    movl _ZN3foo1BE, %eax ; move B into eax
    ; -- NOT a compile-time constant
    movl %eax, -16(%ebp) ; this is also stupid,
    ; but not related to my problem
    jmp .L7 ; goto .L7
    ..L6:
    movl _ZN3foo1AE, %eax ; move A into eax
    ; again, not a compile-time constant
    movl %eax, -16(%ebp) ; more g++ stupidity
    ..L7:
    movl -16(%ebp), %eax ; and where we realize the stupidity
    movl %eax, -8(%ebp) ; the rest is just creating the
    ; std::pair and returning it
    subl $4, %esp
    movl 12(%ebp), %eax
    addl -8(%ebp), %eax
    incl %eax
    movb (%eax), %al
    movb %al, -9(%ebp)
    leal -9(%ebp), %eax
    pushl %eax
    movl 12(%ebp), %edx
    movl -8(%ebp), %eax
    movb (%eax,%edx), %al
    movb %al, -10(%ebp)
    leal -10(%ebp), %eax
    pushl %eax
    pushl 8(%ebp)
    ..LCFI17:
    call _ZNSt4pairIhhEC1ERKhS2_
    addl $16, %esp
    movl 8(%ebp), %eax
    leave
    ret $4
    -----------------------------------------------------

    This is the assembly output for mingw/g++ 3.4.2

    -----------------------------------------------------
    __ZNK3foo6methodEb:
    pushl %ebp
    movl %esp, %ebp
    subl $40, %esp
    movl 12(%ebp), %eax
    movb %al, -1(%ebp) ; move redundant (%al) to stack
    cmpb $0, -1(%ebp) ; if redundant is false
    je L12 ; goto L12
    movl $8184, -16(%ebp) ; put B into offset
    ; B IS a compile-time constant
    jmp L13 ; goto L13
    L12:
    movl $8, -16(%ebp) ; move A into offset
    ; again, A is a compile-time constant
    L13:
    movl -16(%ebp), %eax ; return std::pair blah blah blah
    movl %eax, -8(%ebp)
    movl 8(%ebp), %eax
    addl -8(%ebp), %eax
    incl %eax
    movzbl (%eax), %eax
    movb %al, -11(%ebp)
    leal -11(%ebp), %eax
    movl %eax, 8(%esp)
    movl 8(%ebp), %edx
    movl -8(%ebp), %eax
    movzbl (%eax,%edx), %eax
    movb %al, -12(%ebp)
    leal -12(%ebp), %eax
    movl %eax, 4(%esp)
    leal -10(%ebp), %eax
    movl %eax, (%esp)
    call __ZNSt4pairIhhEC1ERKhS2_
    movzwl -10(%ebp), %eax
    leave
    ret
    -----------------------------------------------------

    The stupid copy from a->stack and back is gone in 3.4.2 also, but that's
    not really related to my problem.

    >
    >
    >>Am I supposed to declare storage space for these constants, or is it
    >>legal here to assume they will become compile-time constnats? What
    >>does the C++ standard say?

    >
    >
    > Since their address is never taken, the 'foo::A' and 'foo::B' are, in
    > fact, compile-time constant expressions that do not require storage.
    > The objects, therefore, don't need to be defined outside of the class
    > definition. g++ 3.3.3 is probably too old. It's even too old and non-
    > compliant in this particular case even with 1998 version of the C++
    > Standard. The standard was amended to allow const statics to be only
    > defined in the class definition if their address is not taken _even_
    > if they are "used" outside the class. [I am too lazy, though, to look
    > it up in the Standard...]


    I was just discussing it on the gcc-help list and need evidence to prove
    it's a g++ bug.

    I think I will go compile g++ 3.4.2 for use on Linux.

    Thanks,

    --John Ratliff
     
    John Ratliff, Oct 16, 2005
    #3
  4. John Ratliff

    Ian Guest

    John Ratliff wrote:
    > I'm trying to find out whether g++ has a bug or not. Wait, don't leave,
    > it's a standard C++ question, I promise.
    >
    > This program will compile and link fine under mingw/g++ 3.4.2, but fails
    > to link under Linux/g++ 3.3.3.
    >
    > ---------------------------------------------
    > #include <iostream>
    > #include <utility>
    >
    > class foo {
    > private:
    > char sram[0x2000];
    >
    > public:
    > static const int A = 0x8;
    > static const int B = 0x1FF8;
    >

    [snip]

    > Am I supposed to declare storage space for these constants, or is it
    > legal here to assume they will become compile-time constnats? What does
    > the C++ standard say?
    >

    In theory yes, but so long as you don't take the address of a static
    const, no.

    If you do take the address of a static constant, it has to be defined in
    the program.

    Ian
     
    Ian, Oct 16, 2005
    #4
  5. John Ratliff

    John Ratliff Guest

    Victor Bazarov wrote:
    > The program is well-formed. 'A' and 'B' are never used outside of
    > the class definition, so they don't need to be defined. That's what
    > 1998 version of the Standard used to say. It was changed a bit in the
    > 2003 version (IIRC) but to give programmers even more leeway.


    From the 1998 C++ standard. 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 (5.19). In
    that case, the member can appear in integral constant expressions within
    its scope. 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."

    "The member shall still be defined in the namespace scope" is the line
    I'm looking at. Doesn't this mean I still have to declare it?

    Thanks,

    --John Ratliff
     
    John Ratliff, Oct 17, 2005
    #5
  6. * John Ratliff:
    > Victor Bazarov wrote:
    > > The program is well-formed. 'A' and 'B' are never used outside of
    > > the class definition, so they don't need to be defined. That's what
    > > 1998 version of the Standard used to say. It was changed a bit in the
    > > 2003 version (IIRC) but to give programmers even more leeway.

    >
    > From the 1998 C++ standard. 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 (5.19). In
    > that case, the member can appear in integral constant expressions within
    > its scope. 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."
    >
    > "The member shall still be defined in the namespace scope" is the line
    > I'm looking at. Doesn't this mean I still have to declare it?


    Yes.

    <url:
    http://gcc.gnu.org/onlinedocs/gcc/Static-Definitions.html#Static-Definitions>

    One solution is to use an enum, which presumably is what those static
    constants were meant to provide a more sensible, typed alternative to.

    I've seen it claimed that the word 'used' means it's OK to use such constants
    in compile time expressions, without defining them in namespace scope, but I
    haven't seen that view substantiated with references to the standard.

    There is a defect report, which has been there since -- November 1997:
    <url: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48>.

    And there is a thorny issue, the whole shebang of static constants of other
    types and initialization specified outside constructor can potentially be
    dragged in, like, physicists didn't want to tackle the issue of quarks because
    if fractional charges like 1/3 were introduced, where would it all end?

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Oct 17, 2005
    #6
  7. * Alf P. Steinbach:
    > * John Ratliff:
    > >
    > > "The member shall still be defined in the namespace scope" is the line
    > > I'm looking at. Doesn't this mean I still have to declare it?

    >
    > Yes.
    >
    > <url:
    > http://gcc.gnu.org/onlinedocs/gcc/Static-Definitions.html#Static-Definitions>
    >
    > One solution is to use an enum, which presumably is what those static
    > constants were meant to provide a more sensible, typed alternative to.
    >
    > I've seen it claimed that the word 'used' means it's OK to use such constants
    > in compile time expressions, without defining them in namespace scope, but I
    > haven't seen that view substantiated with references to the standard.
    >
    > There is a defect report, which has been there since -- November 1997:
    > <url: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48>.
    >
    > And there is a thorny issue, the whole shebang of static constants of other
    > types and initialization specified outside constructor can potentially be
    > dragged in, like, physicists didn't want to tackle the issue of quarks because
    > if fractional charges like 1/3 were introduced, where would it all end?


    Oh, there is a _proposed resolution_, <url:
    http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#454>.

    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 [note1] an integral constant expression (5.19). In that case,
    the member can appear in integral constant expressions. No definition of the
    member is required, unless an lvalue expression that designates it is
    potentially evaluated and either used as operand to the built-in unary &
    operator [note 2] or directly bound to a reference.

    If a definition exists, it shall be at namespace scope and shall not
    contain an initializer.


    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Oct 17, 2005
    #7
  8. John Ratliff

    John Ratliff Guest

    Alf P. Steinbach wrote:
    > * Alf P. Steinbach:
    >
    >>* John Ratliff:
    >>
    >>>"The member shall still be defined in the namespace scope" is the line
    >>>I'm looking at. Doesn't this mean I still have to declare it?

    >>
    >>Yes.
    >>
    >><url:
    >>http://gcc.gnu.org/onlinedocs/gcc/Static-Definitions.html#Static-Definitions>
    >>
    >>One solution is to use an enum, which presumably is what those static
    >>constants were meant to provide a more sensible, typed alternative to.
    >>
    >>I've seen it claimed that the word 'used' means it's OK to use such constants
    >>in compile time expressions, without defining them in namespace scope, but I
    >>haven't seen that view substantiated with references to the standard.
    >>
    >>There is a defect report, which has been there since -- November 1997:
    >><url: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48>.
    >>
    >>And there is a thorny issue, the whole shebang of static constants of other
    >>types and initialization specified outside constructor can potentially be
    >>dragged in, like, physicists didn't want to tackle the issue of quarks because
    >>if fractional charges like 1/3 were introduced, where would it all end?

    >
    >
    > Oh, there is a _proposed resolution_, <url:
    > http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#454>.
    >
    > 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 [note1] an integral constant expression (5.19). In that case,
    > the member can appear in integral constant expressions. No definition of the
    > member is required, unless an lvalue expression that designates it is
    > potentially evaluated and either used as operand to the built-in unary &
    > operator [note 2] or directly bound to a reference.
    >
    > If a definition exists, it shall be at namespace scope and shall not
    > contain an initializer.
    >
    >


    Okay, so, technically, it IS required according to the current standard,
    but most compilers implement the proposed resolution.

    But to be a correct program, I need to define storage space until the
    proposed resolution becomes part of the accepted standard.

    Thanks,

    --John Ratliff
     
    John Ratliff, Oct 17, 2005
    #8
  9. John Ratliff wrote:
    > Alf P. Steinbach wrote:
    >
    >> * Alf P. Steinbach:
    >>
    >>> * John Ratliff:
    >>>
    >>>> "The member shall still be defined in the namespace scope" is the
    >>>> line I'm looking at. Doesn't this mean I still have to declare it?
    >>>
    >>>
    >>> Yes.
    >>>
    >>> <url:
    >>> http://gcc.gnu.org/onlinedocs/gcc/Static-Definitions.html#Static-Definitions>
    >>>
    >>>
    >>> One solution is to use an enum, which presumably is what those static
    >>> constants were meant to provide a more sensible, typed alternative to.
    >>>
    >>> I've seen it claimed that the word 'used' means it's OK to use such
    >>> constants
    >>> in compile time expressions, without defining them in namespace
    >>> scope, but I
    >>> haven't seen that view substantiated with references to the standard.
    >>>
    >>> There is a defect report, which has been there since -- November 1997:
    >>> <url: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#48>.
    >>>
    >>> And there is a thorny issue, the whole shebang of static constants of
    >>> other
    >>> types and initialization specified outside constructor can
    >>> potentially be
    >>> dragged in, like, physicists didn't want to tackle the issue of
    >>> quarks because
    >>> if fractional charges like 1/3 were introduced, where would it all end?

    >>
    >>
    >>
    >> Oh, there is a _proposed resolution_, <url:
    >> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#454>.
    >>
    >> 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 [note1] an integral constant expression (5.19). In that
    >> case,
    >> the member can appear in integral constant expressions. No definition
    >> of the
    >> member is required, unless an lvalue expression that designates it is
    >> potentially evaluated and either used as operand to the built-in unary &
    >> operator [note 2] or directly bound to a reference.
    >>
    >> If a definition exists, it shall be at namespace scope and shall not
    >> contain an initializer.
    >>
    >>

    >
    > Okay, so, technically, it IS required according to the current standard,
    > but most compilers implement the proposed resolution.
    >
    > But to be a correct program, I need to define storage space until the
    > proposed resolution becomes part of the accepted standard.


    No, _technically_, since neither constant was used _outside_ the class
    definition, there is no need for the definition at the namespace scope.
    Now, if your compiler requires it, the compiler is non-compliant. But,
    in that case, just to let the compilation through, you _technically_ need
    the definition. Or, change the compiler.

    V
     
    Victor Bazarov, Oct 17, 2005
    #9
  10. * Victor Bazarov:
    >
    > No, _technically_, since neither constant was used _outside_ the class
    > definition, there is no need for the definition at the namespace scope.


    I don't think that's implied.

    But the standard's wording is not exactly clear...

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Oct 17, 2005
    #10
  11. Alf P. Steinbach wrote:
    > * Victor Bazarov:
    >
    >>No, _technically_, since neither constant was used _outside_ the class
    >>definition, there is no need for the definition at the namespace scope.

    >
    >
    > I don't think that's implied.
    >
    > But the standard's wording is not exactly clear...
    >


    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 (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 program and the
    namespace scope definition shall not contain an initializer."

    By the rules of logic I've learned, the last sentence means "if it is not
    used in the program, the member need not be defined in a namespace scope",
    'it' meaning the static data member of const integral or enum type.

    What's not exactly clear about it?

    V
     
    Victor Bazarov, Oct 17, 2005
    #11
  12. John Ratliff

    John Ratliff Guest

    Alf P. Steinbach wrote:
    > * Victor Bazarov:
    >
    >>No, _technically_, since neither constant was used _outside_ the class
    >>definition, there is no need for the definition at the namespace scope.

    >
    >
    > I don't think that's implied.
    >
    > But the standard's wording is not exactly clear...
    >


    The 2003 standard made some changes, but I'm not sure it's any more clear.

    "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
    (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 program and the namespace scope definition shall not
    contain an initializer."

    I got this from a post on the gcc-help list.

    I interpret this to mean you are required to add a namespace scope
    definition if you use the variable in the program. This requires us to
    define the term 'use'.

    I would say this means I am required to add a namespace scope
    definition, but not use an initializer. This would mean that I could use
    the constant value both within the class (e.g. array[const_var_id]) and
    in the program.

    If the compiler optimized well, it would realize that the there is no
    need for external linkage and make this a compile-time constant and
    replace the values like a type-safe namespace-local define. If the
    compiler was not as good at this (g++ 3.3 at times in what I am sure is
    a bug, even though it doesn't violate the standard), it would not
    realize this and use external linkage.

    A slightly different program, which I think is correct according to the
    standard:

    -----------------------------------------------------------------
    #include <iostream>

    class foo {
    public:
    static const unsigned int SRAM_SIZE = 0x2000;

    static const int CHECKSUM_OFFSET = 0x8;
    static const int CHECKSUM_OFFSET2 = 0x1FF8;

    foo();
    unsigned char getChecksum(bool redundant = false) const;

    private:
    char sram[SRAM_SIZE];
    };

    const int foo::CHECKSUM_OFFSET;
    const int foo::CHECKSUM_OFFSET2;

    foo::foo() {
    sram[CHECKSUM_OFFSET] = 1;
    sram[CHECKSUM_OFFSET2] = 2;
    }

    unsigned char foo::getChecksum(bool redundant) const {
    int offset = (redundant ? CHECKSUM_OFFSET2 : CHECKSUM_OFFSET);

    return sram[offset];
    }

    int main(int, char **) {
    foo f;
    unsigned char c1 = f.getChecksum();
    unsigned char c2 = f.getChecksum(true);

    std::cout << "c1 = " << static_cast<int>(c1) << '\n';
    std::cout << "c2 = " << static_cast<int>(c2) << '\n';

    return 0;
    }
    -----------------------------------------------------------------

    In the foo::getChecksum() method, I didn't stick the ternary operator
    into the return call because this doesn't trigger the g++ 3.3 bug. If
    you replace it with a simple

    return sram[redundant ? CHECKSUM_OFFSET2 : CHECKSUM_OFFSET];

    g++ 3.3 will treat them as compile time constants not requiring external
    linkage. However, it will not remove the definitions from the assembly
    output, so they are still in the program, even though it never uses
    them. This is odd, but seemingly conforming behavior. There was no need
    to add SRAM_SIZE to the definition as it is not used anywhere in the
    program. However, I don't think it violates the standard if I had done this.

    I also don't think it would matter if I had defined the functions inline
    inside the class-def as I did in the earlier example. I would consider
    this to be part of the program, not part of the class-def, but maybe I
    am wrong here. In my real program, the function is not inline, so I
    shouldn't have used an example that was.

    Thanks,

    --John Ratliff
     
    John Ratliff, Oct 17, 2005
    #12
  13. * Victor Bazarov:
    > Alf P. Steinbach wrote:
    > > * Victor Bazarov:
    > >
    > >>No, _technically_, since neither constant was used _outside_ the class
    > >>definition, there is no need for the definition at the namespace scope.

    > >
    > >
    > > I don't think that's implied.
    > >
    > > But the standard's wording is not exactly clear...
    > >

    >
    > 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 (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 program and the
    > namespace scope definition shall not contain an initializer."
    >
    > By the rules of logic I've learned, the last sentence means "if it is not
    > used in the program, the member need not be defined in a namespace scope",
    > 'it' meaning the static data member of const integral or enum type.
    >
    > What's not exactly clear about it?


    E.g. "used" and "in the program". Just to take the latter, where else could
    the constant be used than in the program? Hence something else was probably
    meant, and your interpretation (if I read you right) that "program" equals
    "the program apart from the class definition" could be right, or wrong, or it
    could be that say five different committee members had five different ideas
    about what it meant, and this vagueness was what all they could agree to...

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Oct 17, 2005
    #13
  14. John Ratliff

    Greg Comeau Guest

    In article <L9M4f.492451$xm3.33227@attbi_s21>,
    John Ratliff <> wrote:
    >Victor Bazarov wrote:
    >> The program is well-formed. 'A' and 'B' are never used outside of
    >> the class definition, so they don't need to be defined. That's what
    >> 1998 version of the Standard used to say. It was changed a bit in the
    >> 2003 version (IIRC) but to give programmers even more leeway.

    >
    > From the 1998 C++ standard. 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 (5.19). In
    >that case, the member can appear in integral constant expressions within
    >its scope. 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."
    >
    >"The member shall still be defined in the namespace scope" is the line
    >I'm looking at. Doesn't this mean I still have to declare it?


    That's what it says but isn't what it meant. What it meant is
    what Victor said, and hence it was acknowledged as a defect
    since requiring the definition in all cases was not the intent
    when member constants were allowed.
    --
    Greg Comeau / Celebrating 20 years of Comeauity!
    Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
    World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
    Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
     
    Greg Comeau, Oct 18, 2005
    #14
  15. John Ratliff

    Greg Comeau Guest

    In article <>,
    Alf P. Steinbach <> wrote:
    >* Victor Bazarov:
    >> Alf P. Steinbach wrote:
    >> > * Victor Bazarov:
    >> >>No, _technically_, since neither constant was used _outside_ the class
    >> >>definition, there is no need for the definition at the namespace scope.
    >> >
    >> > I don't think that's implied.
    >> >
    >> > But the standard's wording is not exactly clear...

    >>
    >> 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 (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 program and the
    >> namespace scope definition shall not contain an initializer."
    >>
    >> By the rules of logic I've learned, the last sentence means "if it is not
    >> used in the program, the member need not be defined in a namespace scope",
    >> 'it' meaning the static data member of const integral or enum type.
    >>
    >> What's not exactly clear about it?

    >
    >E.g. "used" and "in the program". Just to take the latter, where else could
    >the constant be used than in the program? Hence something else was probably
    >meant, and your interpretation (if I read you right) that "program" equals
    >"the program apart from the class definition" could be right, or wrong, or it
    >could be that say five different committee members had five different ideas
    >about what it meant, and this vagueness was what all they could agree to...


    The intent was supposed to be better than that, that is to say,
    "used" is a defined term, see 3.2p2 of C++03. More clarification
    is still in progress though.
    --
    Greg Comeau / Celebrating 20 years of Comeauity!
    Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
    World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
    Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
     
    Greg Comeau, Oct 18, 2005
    #15
    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:
    882
    John C. Bollinger
    Oct 22, 2003
  2. John David Ratliff

    static constants...

    John David Ratliff, Nov 7, 2003, in forum: C++
    Replies:
    1
    Views:
    404
    Gianni Mariani
    Nov 7, 2003
  3. Bill Woessner

    static constants

    Bill Woessner, Nov 20, 2003, in forum: C++
    Replies:
    2
    Views:
    314
    NFish
    Nov 21, 2003
  4. Raymond Hettinger
    Replies:
    8
    Views:
    327
    Daniel 'Dang' Griffith
    Apr 21, 2004
  5. Raymond Hettinger
    Replies:
    0
    Views:
    324
    Raymond Hettinger
    Apr 19, 2004
Loading...

Share This Page