Member initialization of arrays of constants

llewelly@dbritsch.dsl.xmission.com llewelly@dbritsch.dsl.xmission.com
Tue Jul 25 10:52:00 GMT 2000


I think we should move this discussion to comp.std.c++ .        
        
> On Sun, 23 Jul 2000 llewelly@dbritsch.dsl.xmission.com wrote:
> 
> >There is nothing in 8.5.1 [dcl.init.aggr] that disallows initializing
> >  a member array of constant type with a brace-enclosed initializer
> >  list.
> 
> Then it seems, I've found a bug in both Borland C++ 5.5 and Visual C++
> 5.0. They throw errors upon compilation of my code examples and
> further related tests. 
> 
> In case of brace-enclosed copy-initialization (_dcl.init.aggr_) of an
>   array of constant chars, BC says: 
> 
> struct C
> {
>     const char c[4];
> };
> 
> Error: Constant member 'C::A::c' in class without constructors

I cannot find wording in the standard that disallows const members
  from classes without constructors.

(Nor have I ever found a C++ compiler that did not have a multitude of
  bugs.)  

> 
> >In both of your examples, A is an aggregate, and can therefor be
> >  initialized with a brace-enclosed initializer list. (See 8.5.1)
> 
> How's that possible, considering the extended example of a class with
> default constructor and, for instance, a non-static member constant of
> aggregate type?

It is possible because 8.5.1 allows it.

> 
> If you say, it _can_ be initialized, shouldn't the following code be
> ill-formed then? Uninitialized const-qualified types, according to
> 12.6.1, 4:
> 
> #include <iostream.h>
> #include <iomanip.h>
> 
> struct A
> {
>     const char c[4];
>     const j;

I presume 'const j' was intended to be 'const int j' .

>     int i;
> 
>     A()
>     {
>         i = 42;
>     }

I do think 12.6.1/4 makes this constructor ill-formed, however, your
  previous examples did not contain user-defined constructors, and
  were aggregates according to 8.5.1; this class is not.

(gcc 2.95.2, and 2.96 20000626 both compile it without errors, and
  that (I belive) *is* a bug, but it is different from your earlier
  examples.) 

> };
> 
> void f()
> {
>     A a;
>     cout << a.i << endl;  // okay, a.i is initialized
>     cout << a.j << endl;  // oops?
>     cout << a.c << endl;  // oops?
> 
>     const A b = { "foo", 1, 2 };  // error
>     // b' must be initialized by constructor, not by `{...}'
> };

> 
> >The fact that there are const-qualified types in involved does not
> >  matter in either of your examples; const qualifed types can be
> >  initialized the same way.
> 
> I'd be forced to make each array of constants static. Else I could not
> perform copy-initialization. 
> 
>   9.2, 4
> 
>   A member-declarator can contain a constant-initializer only if
>   it declares a static member (_class.static_) of integral or
>   enumeration type, see _class.static.data_.

A member-declarator is a declaration of a member inside a class
  declaration. 

In your 'Example 2', the initialization was not in the class
  declaration, and so I do not see how 9.2/4 applies.

> 
> If you mean, that the brace-enclosed initializer-list is a special
> case which can only initialize static constant member aggregates, this
> would make sense.

hm? No, I did not mean that at all. Given:

  struct A
  {
    const char a[4];
    int i;
  };

A has no user-declared constructors, no private or protected nonstatic
  data members, no base classes, and no virtual functions. [8.5.1/1]
  So A is an aggregate type; any instance of A may be initialized by
  brace enclosed initialization.

An instance of A which is a static const member of a non-aggregate
  type is still itself an aggregate, and can be initialized by
  brace enclosed initialization;
  
  class C
  {
    static const A a;
  };

  const A C::a = { 'T','E','S','T', 2 };

  is well-formed. This does not require special cases; it is a
    natural result of combing the rules on how static members are
    initialized (9.4.2), with the rules for initializing aggregates
    (8.5.1).

> 
> >(If const-qualifed members could not be initialized, there would no
> >  use for them.)

At the time I made this comment, I was thinking of static const
  members. 

> 
> Well, const-qualified members can be initialized via the ctor's
> mem-initializer list.

static data members, const or not, cannot be initialized via the
  ctor's mem-initializer list, as they are per class and not per
  instance. 

> But what about member arrays of const-qualified
> basic types? 
> 
> >(The rule you are probably thinking of is probably based on 12.6.2/4,
> >  which does not apply to static data members, or to initialization of an
> >  aggregate via a brace-enclosed intializer list.)
> 
> Yes. Whenever I add a constructor, I can forget about using the
> brace-enclosed initializer-list. Hmmm...

That is what 8.5.1/1 says.


[snip]



More information about the Gcc-bugs mailing list