Topic: definition of


Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Mon, 3 Dec 2001 18:38:50 GMT
Raw View
In article <3c09e157$1@news.microsoft.com>, Jason Shirk says...
>
>Is the following a legal program?
>
>//--- begin
>template <class T>
>struct Outer {
>    struct Inner1 {
>        struct Inner2 : T { };
>        void func() {
>            typename T::Other t;
>        }
>    };
>};
>
>Outer<int>::Inner1 inner1;
>//--- end
>
>14.7.1 says that when a class template specialization is referenced, it's
>members declarations are implicitly instantiated.  The members'
>definitions are not implicitly instantiated unless referenced.

... because of 14.7.1/1 and /9, to be precise.

>Above, Outer<int>::Inner1 is referenced, so the definition should be
>implicitly instantiated.  Outer<int>::Inner1 is not a class template, and
>therefore I would expect Outer<int>::Inner1::Inner2 and
>Outer<int>::Inner1::func to be instaniated when Outer<int>::Inner1 is
>instantiated.

There is a difference in instantiating the declaration and definition.
The declarations of member classes of Outer<int> are instantiated,
because of 14.7.1/1. The definition of Outer<int> member classes are not.
Since the definition of Outer<int>::Inner1 isn't instantiated, its members
aren't instantiated, neither its declarations nor its definitions.

> However, both of these members cannot be instantiated with
>T=int, so a compiler should issue an error.

On instantiation of the definition of Outer<int>::Inner1. Which
doesn't happen.

>Both Comeau 4.2.45.2 and GCC 2.95 compile this without any error, Borland
>gives an error saying 'int' is not a valid base class.  This would imply
>Borland is instantiating Inner2 when Inner1 is instantiated, but Comeau
>and GCC do not.

>So, my question is:
>
>Is a member of a nested member also a member of a class template?  If so,
>is there wording in the standard or a defect report that explains this?
>If not, am I missing something, or are Comeau and GCC non-conforming in
>this regard?
>
>Jason Shirk

I think you're missing that the instantiation of the member class Inner1
is only an instantiation of its declaration, without checking its
definition. And that stops the instantiation process. To me it looks like
Borland incorrectly instantiates the definition of member class
Outer<int>::Inner1. ( Per 14.7.1/9 )

Regards,

--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.nl

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Jason Shirk" <jasonsh__n_o_s_p_a_m__@microsoft.com>
Date: Mon, 3 Dec 2001 19:27:09 GMT
Raw View
"Michiel Salters" <Michiel.Salters@cmg.nl> wrote in message
news:LhJO7.46653$xS6.75941@www.newsranger.com...
> In article <3c09e157$1@news.microsoft.com>, Jason Shirk says...
> >
> >Is the following a legal program?
> >
> >//--- begin
> >template <class T>
> >struct Outer {
> >    struct Inner1 {
> >        struct Inner2 : T { };
> >        void func() {
> >            typename T::Other t;
> >        }
> >    };
> >};
> >
> >Outer<int>::Inner1 inner1;
> >//--- end
> >
> >14.7.1 says that when a class template specialization is referenced, it's
> >members declarations are implicitly instantiated.  The members'
> >definitions are not implicitly instantiated unless referenced.
>
> ... because of 14.7.1/1 and /9, to be precise.
>
> >Above, Outer<int>::Inner1 is referenced, so the definition should be
> >implicitly instantiated.  Outer<int>::Inner1 is not a class template, and
> >therefore I would expect Outer<int>::Inner1::Inner2 and
> >Outer<int>::Inner1::func to be instaniated when Outer<int>::Inner1 is
> >instantiated.
>
> There is a difference in instantiating the declaration and definition.
> The declarations of member classes of Outer<int> are instantiated,
> because of 14.7.1/1. The definition of Outer<int> member classes are not.
> Since the definition of Outer<int>::Inner1 isn't instantiated, its members
> aren't instantiated, neither its declarations nor its definitions.
>

The following line of code (from above) instantiates the definition of
Outer<int>::Inner1:

Outer<int>::Inner1 inner1;

because the compiler needs to know the size to create an instance of it.

Jason Shirk



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Andrei Iltchenko" <iltchenko@yahoo.com>
Date: Tue, 4 Dec 2001 18:42:40 GMT
Raw View
"Michiel Salters" <Michiel.Salters@cmg.nl> wrote in message
news:LhJO7.46653$xS6.75941@www.newsranger.com...

> >Is the following a legal program?
> >
> >//--- begin
> >template <class T>
> >struct Outer {
> >    struct Inner1 {
> >        struct Inner2 : T { };
> >        void func() {
> >            typename T::Other t;
> >        }
> >    };
> >};
> >
> >Outer<int>::Inner1 inner1;
> >//--- end
> >
> >So, my question is:
> >
> >Is a member of a nested member also a member of a class template?  If so,
> >is there wording in the standard or a defect report that explains this?
> >If not, am I missing something, or are Comeau and GCC non-conforming in
> >this regard?
> >
> >Jason Shirk
>
> I think you're missing that the instantiation of the member class Inner1
> is only an instantiation of its declaration, without checking its
> definition. And that stops the instantiation process.

That would be the case if the last declaration in the code sample read
something like
Outer<int>   outer;

Based on 14.7.1/1, the last line of Jason's code example requires implicit
instantiation of the specialization 'Outer<int>::Inner1' simply because the
compiler needs to see if Inner1's constructor and destructor have side
effects. See the second paragraph of 3.7.1.


Regards,

Andrei Iltchenko.






---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Tue, 4 Dec 2001 18:44:34 GMT
Raw View
In article <3c0bd188$1@news.microsoft.com>, Jason Shirk says...
>
>
>"Michiel Salters" <Michiel.Salters@cmg.nl> wrote in message
>news:LhJO7.46653$xS6.75941@www.newsranger.com...
>> In article <3c09e157$1@news.microsoft.com>, Jason Shirk says...
>> >
>> >Is the following a legal program?
>> >
>> >//--- begin
>> >template <class T>
>> >struct Outer {
>> >    struct Inner1 {
>> >        struct Inner2 : T { };
>> >        void func() {
>> >            typename T::Other t;
>> >        }
>> >    };
>> >};
>> >
>> >Outer<int>::Inner1 inner1;
>> >//--- end
>> >
>> >14.7.1 says that when a class template specialization is referenced, it's
>> >members declarations are implicitly instantiated.  The members'
>> >definitions are not implicitly instantiated unless referenced.
>>
>> ... because of 14.7.1/1 and /9, to be precise.
>>
>> >Above, Outer<int>::Inner1 is referenced, so the definition should be
>> >implicitly instantiated.  Outer<int>::Inner1 is not a class template, and
>> >therefore I would expect Outer<int>::Inner1::Inner2 and
>> >Outer<int>::Inner1::func to be instaniated when Outer<int>::Inner1 is
>> >instantiated.
>>
>> There is a difference in instantiating the declaration and definition.
>> The declarations of member classes of Outer<int> are instantiated,
>> because of 14.7.1/1. The definition of Outer<int> member classes are not.
>> Since the definition of Outer<int>::Inner1 isn't instantiated, its members
>> aren't instantiated, neither its declarations nor its definitions.
>>
>
>The following line of code (from above) instantiates the definition of
>Outer<int>::Inner1:
>
>Outer<int>::Inner1 inner1;
>
>because the compiler needs to know the size to create an instance of it.
>
>Jason Shirk

I'm not sure how I missed that. Duh.

Anyway, let's try it again.
As you said, the definition of member class Outer<int>::Inner1 is needed.

Inner1 is not a template itself. It is a member of Outer<int>, which is
an implicit instantiation. By 14.7.1/9, Inner1 is instantiated.

However, 14.7.1 only describes implicit instantiation of class
templates and function templates. It doesn't cover what happens
when Inner1 is instantiated. By my reading, Outer<int>::Inner1 is
a normal member class. Ergo, 14.7.1/9 doesn't apply. So, when
Inner1 is instantiated, all of it is compiled. Compiling the
declaration of Outer<int>::Inner1::Inner2, name lookup happens
according to 14.6/1 (we're within a template definition). 'T' is
int, of course, which is an invalid base class, and an error should
be generated. When func is compiled, T::Other is looked up according
to 14.6.2, but the difference doesn't matter. T is int, and
int::Outer is in error. So that should give a second error.

14.7.1/9 does not apply to members of members classes of templates.
I don't know if that was intentional.

Regards.

--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.nl

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]