This is the mail archive of the libstdc++@sourceware.cygnus.com mailing list for the libstdc++ project. See the libstdc++ home page for more information.


[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index] [Subject Index] [Author Index] [Thread Index]

Re: Static data members in template declarations



> 
> >>>>> "Jason" == Jason Merrill <jason@cygnus.com> writes:
> 
>     Jason> Let's make it work.
> 
> Simple enough to say. :-)  (By the way, since the example below is
> mine, I would have appreciated being in the loop on whatever
> discussion was taking place about it.)
> 
> In any case, we need to understand under exactly which circumstances
> these things match.  John, do you have a proposal handy?  For example,
> what about:
> 
>   template <class T>
>   struct B {
>     enum E { a = 1 
>              /* So that John will be happy with the array. :-) */ 
> 	   }; 
>   };
> 
>   template <class T>
>   struct D : public B<T> {
>     static T t[B<T>::a];
>   };
> 
>   template <class T>
>   T S<T>::t[S<T>::a];

      // Is "S" supposed to be "D"?

> 
> In the same way as for my original example, you can reason that
> `S<T>::a' must refer to the same thing as `B<T>::a', even though
> `B<T>::a' is dependent, and not resolved in the first phase of lookup.
> There is no `a' in `S<T>' proper, so if `S<T>::a' is going to make
> sense at all, it must be because it is in fact `B<T>::a'.  Is the
> compiler supposed to figure this out though?  What if the last line
> says just plain `a', not `S<T>::a'?
> 

I don't have a proposal at this point, but an informal version of what
I have been thinking of is something like the following.

Within a class template (such as B above) "a" can be referred to as
simply "a", as "B::a", or as "B<T>::a".  When you define "t" later,
you can use any one of these equivalent forms within the class and
any of the equivalent forms in the definition later (assuming the
form is semantically valid at that point later).  

In other words, this should be allowed:

  template <class T>
  struct B {
    enum E { a = 1 }; 
    static T t[a];
    static T t2[a];
    static T t3[a];
  };

  template <class T> T B<T>::t[a];
  template <class T> T B<T>::t2[B::a];
  template <class T> T B<T>::t3[B<T>::a];

Note that if the type of the static data member were something like "B<T>::X",
"B::X" would not be valid in the type field because it can only be used after
the class has been "reactivated" at the :: in the declarator.

There once was a concept in the WP that gave special treatment to things
like "B" and "B<T>" because you know more about the "current instance"
than you do about any other instance, so a different set of equivalence
rules can be applied.  This concept needs to be restored to make the
rules clear for cases like this.

For example, in your modified example above, the rules are completely different
because the array size in "D<T>" comes from "B<T>" and when the definition
of "D" is scanned, you really don't know anything about the instance of "B"
that will actually be used for an instantiation.  There could be specializations
declared that don't even have an "a" member.  So, when a declaration uses
anything other than the current instance, a later declaration must use exactly
the same declaration modulo things like template parameter names.

Does this sound like a sensible direction to you?

John.