This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: PR3042
- To: David Edelsohn <dje at watson dot ibm dot com>, Jason Merrill <jason_merrill at redhat dot com>
- Subject: Re: PR3042
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Mon, 11 Jun 2001 12:47:29 -0700
- cc: "gdr at codesourcery dot com" <gdr at codesourcery dot com>, "bkoz at nabi dot net" <bkoz at nabi dot net>, "libstdc++ at gcc dot gnu dot org" <libstdc++ at gcc dot gnu dot org>
--On Monday, June 11, 2001 03:29:35 PM -0400 David Edelsohn
<dje@watson.ibm.com> wrote:
> Are multiple modules with
>
> template <typename T>
> int S<double>::i = 1;
This is not legal C++, and again that really confuses the issues. If
we accept this code, we are broken.
Here is a brief tutorial:
- An ordinary data member is just what C programmers call a field.
A `static' data member is a global object, but lexically scoped
within a class. You could simulate these in C by prefixing
the data member name with the name of the struct you wanted to
associate it with.
There are special rules for `const' static data members, so
let's ignore them.
A non-const static data member must be declared -- in the class
declaration -- and defined, outside of it. For example:
struct S {
static int i; // Declaration
}
int S::i; // Definition
The former is equivalent to:
extern int S__i;
in C; the latter is equivalent to:
int S__i;
All the same rules about storage allocation and such hold.
- Templates make things more complex. Now, you have:
template <class T> struct S {
static int i; // Declaration
};
template <class T>
int S<T>::i; // Definition
By themselves, neither of these things allocate any storage --
no type has been specified for T. You have to "instantiate"
the template. You can do this "implicitly" by talking about
`S<T>::i' for some choice of `T'. For example:
int j = S<int>::i;
Or, you can do it "explicitly" by writing:
template int S<int>::i;
You are not allowed to add an initializer in the explicit
instantiation case -- you are just asking the compiler to
fill in the `T' and allocate storage. If you want an
initializer, you always add it to the lines marked `Definition'
above.
Because the language says you can have multiple implicit
instantiations of the same thing, we make `S<int>::i' weak
when implicitly instantiated. The linker merges all the
copies.
The language says you can only have one explicit instantiation.
I thought that we therefore emitted it as strong, but Jason
implied otherwise, and he may well be right.
>
> or
>
> template <typename T>
> int S<T>::i = 1;
>
> allowed? I would have thought that at least the former would produce a
> STRONG symbol in the data section.
The former is invalid C++. The second produces no storage because
there is no instantiation.
>
> Both of the examples produces references but no storage allocation
> in GCC 3.0. Without an assignment, both produce common symbols.
>
> Is Mark's proposal that only
>
> template <typename T>
> int S<double>::i;
>
> was suppose to allocate storage?
No -- that's invald C++.
My proposal was that only `template int S<double>::i;' allocate storage.
In other words, only an explicit instantiation will allocate storage,
independently of whether or not there is an initializer. Right now,
we allocate storage for all explicit instantiations, and implicit
instantiations of data members that do not have initializers.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com