Topic: Order of initializlation and templates.


Author: kanze@alex.gabi-soft.fr (James Kanze)
Date: Sun, 4 May 2003 21:47:00 +0000 (UTC)
Raw View
jhs@edg.com ("John H. Spicer") writes:

|>  James Kanze wrote:
|>  > jhs@edg.com ("John H. Spicer") wrote in message
|>  > news:<3EB03AA1.3070009@edg.com>...

|>  >>>According to my understanding of the order of initialization,
|>  >>>C<int>::myD should be initialized before C<int>::instance,
|>  >>>since both are defined in the same translation unit, and
|>  >>>C<int>::myD is defined before C<int>::instance; this results in
|>  >>>the output 1.  Both g++ (3.2.2) and Sun CC (5.1) initialize
|>  >>>C<int>::instance first, however, which results in the output 0
|>  >>>-- from discussions in fr.comp.lang.c++, I gather that other
|>  >>>compilers have the same problem.

|>  >>This was clarified by core issue #270, which was adopted in
|>  >>April of 2002, but is not part of the TC that was just issued.
|>  >>It clarifies that the order of initialization of template static
|>  >>data members is unspecified both relative to other template
|>  >>static data members and to other objects of static storage
|>  >>duration.

|>  > OK.  I understand the arguments the other two posters put forth.
|>  > But the paragraph that was cited doesn't say anything about
|>  > order of instantiation.  The order of instantiation of objects
|>  > is based on the *lexical* order, and the only lexical thingy I
|>  > could find is the template definition.

|>  The order of instantiation is not (and cannot) be important.

Agreed.  There are really only two possibilities: unspecified, or the
order of the template definitions (of the static variables, not of the
class).

|>  Your translation unit may (or may not) cause the instantiation of
|>  some number of template static data members.  Some compilers may
|>  choose to instantiate all of them an drop some of the
|>  instantiations at link time if they are discovered elsewhere.
|>  Other implementations may find the instantiations elsewhere and
|>  not instantiate any of them in your translation unit.

|>  > I have no problem with it being undefined -- for practical
|>  > reasons, if nothing else.  There's no point in standardizing
|>  > something that cannot be reasonably implemented, and from what
|>  > little I know about templates, imposing an order would seem to
|>  > come under that category.  It also leaves the issue open -- if
|>  > someone comes up with a good solution in the future, we can
|>  > always defined it.  But it really needed to be said.  And I
|>  > presume that this decision also holds for static members of
|>  > exported template classes.  There is a difference.  The order in
|>  > my example above could presumably be different between different
|>  > compilation units, with no violation of the one definition rule.
|>  > If the variable definitions were exported, however, they would
|>  > only occur in a single compilation unit.  Maybe when we get some
|>  > experience with export, we can think of defining it there.  (But
|>  > let's get the experience first.  I think I'm going to telecharge
|>  > Comeau this week-end:-).  Even if I can only use it on personal
|>  > experiments.)

|>  Whether the templates are exported or not is a separate issue.
|>  With export, the template definitions appear in only one place,
|>  but that doesn't mean the instantiations are located in that same
|>  one place.  Export is a source model, not an instantiation model.
|>  In the EDG compiler we support several instantiation models, and
|>  export can be used with any of them.  Examples of instantiation
|>  models are our prelinker-directed model, and the "instantiate
|>  everywhere and let the linker weed out duplicates" model.

Agreed.  My only point about export is that it is only in exported
templates that we could possibly base the order on the lexical order
of the template definitions (supposing we wanted to, of course); in
all other cases, the definitions may occur in different translation
units, in different orders.

--=20
James Kanze                                  mailto:kanze@gabi-soft.fr
Conseils en informatique orient=E9e objet/
                      Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France  Tel. +33 1 41 89 80 93

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: Fri, 2 May 2003 17:44:28 +0000 (UTC)
Raw View
jhs@edg.com ("John H. Spicer") wrote in message
news:<3EB03AA1.3070009@edg.com>...
> James Kanze wrote:
> > Given the following code:

> >     #include <iostream>
> >     #include <ostream>

> >     template< typename T >
> >     struct D
> >     {
> >         D() : i( 1 ) {}
> >         int i ;
> >     } ;

> >     template< typename T >
> >     struct C
> >     {
> >         C() : i( myD.i ) {}
> >         static D<T> myD ;
> >         static C<T> instance ;
> >         int i ;
> >     } ;

> >     template< typename T >
> >     D<T> C<T>::myD ;

> >     template< typename T >
> >     C<T> C<T>::instance ;

> >     int
> >     main()
> >     {
> >         std::cout << C<int>::instance.i << '\n' ;
> >         return 0 ;
> >     }

> > What should the program output?

> > According to my understanding of the order of initialization,
> > C<int>::myD should be initialized before C<int>::instance, since
> > both are defined in the same translation unit, and C<int>::myD is
> > defined before C<int>::instance; this results in the output 1.  Both
> > g++ (3.2.2) and Sun CC (5.1) initialize C<int>::instance first,
> > however, which results in the output 0 -- from discussions in
> > fr.comp.lang.c++, I gather that other compilers have the same
> > problem.

> This was clarified by core issue #270, which was adopted in April of
> 2002, but is not part of the TC that was just issued.  It clarifies
> that the order of initialization of template static data members is
> unspecified both relative to other template static data members and to
> other objects of static storage duration.

OK.  I understand the arguments the other two posters put forth.  But
the paragraph that was cited doesn't say anything about order of
instantiation.  The order of instantiation of objects is based on the
*lexical* order, and the only lexical thingy I could find is the
template definition.

I have no problem with it being undefined -- for practical reasons, if
nothing else.  There's no point in standardizing something that cannot
be reasonably implemented, and from what little I know about templates,
imposing an order would seem to come under that category.  It also
leaves the issue open -- if someone comes up with a good solution in the
future, we can always defined it.  But it really needed to be said.

And I presume that this decision also holds for static members of
exported template classes.  There is a difference.  The order in my
example above could presumably be different between different
compilation units, with no violation of the one definition rule.  If the
variable definitions were exported, however, they would only occur in a
single compilation unit.  Maybe when we get some experience with export,
we can think of defining it there.  (But let's get the experience
first.  I think I'm going to telecharge Comeau this week-end:-).  Even
if I can only use it on personal experiments.)

--
James Kanze             GABI Software             mailto:kanze@gabi-soft.fr
Conseils en informatique orient   e objet/
                           Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, T   l. : +33 (0)1 30 23 45 16

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@integrable-solutions.net (Gabriel Dos Reis)
Date: Fri, 2 May 2003 18:42:55 +0000 (UTC)
Raw View
kanze@gabi-soft.de (James Kanze) writes:

[...]

| OK.  I understand the arguments the other two posters put forth.  But
| the paragraph that was cited doesn't say anything about order of
| instantiation.  The order of instantiation of objects is based on the
| *lexical* order,

The lexical order of what exactly?  The key point is there.

| and the only lexical thingy I could find is the
| template definition.

Yes, and a template definition is -not- an object definition.  It is
just that:  A template, from which instantiations can happen.  And in
practice, in the only you can determine that a template instantiation
needs another template is, umm , by instantiating i.e. defining.

--
Gabriel Dos Reis, gdr@integrable-solutions.net

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jhs@edg.com ("John H. Spicer")
Date: Fri, 2 May 2003 21:30:25 +0000 (UTC)
Raw View

James Kanze wrote:
> jhs@edg.com ("John H. Spicer") wrote in message
> news:<3EB03AA1.3070009@edg.com>...
>

>>
>
>>>According to my understanding of the order of initialization,
>>>C<int>::myD should be initialized before C<int>::instance, since
>>>both are defined in the same translation unit, and C<int>::myD is
>>>defined before C<int>::instance; this results in the output 1.  Both
>>>g++ (3.2.2) and Sun CC (5.1) initialize C<int>::instance first,
>>>however, which results in the output 0 -- from discussions in
>>>fr.comp.lang.c++, I gather that other compilers have the same
>>>problem.
>>
>
>>This was clarified by core issue #270, which was adopted in April of
>>2002, but is not part of the TC that was just issued.  It clarifies
>>that the order of initialization of template static data members is
>>unspecified both relative to other template static data members and to
>>other objects of static storage duration.
>
>
> OK.  I understand the arguments the other two posters put forth.  But
> the paragraph that was cited doesn't say anything about order of
> instantiation.  The order of instantiation of objects is based on the
> *lexical* order, and the only lexical thingy I could find is the
> template definition.

The order of instantiation is not (and cannot) be important.  Your translation
unit may (or may not) cause the instantiation of some number of template static
data members.  Some compilers may choose to instantiate all of them an drop some
of the instantiations at link time if they are discovered elsewhere.  Other
implementations may find the instantiations elsewhere and not instantiate any of
them in your translation unit.

>
> I have no problem with it being undefined -- for practical reasons, if
> nothing else.  There's no point in standardizing something that cannot
> be reasonably implemented, and from what little I know about templates,
> imposing an order would seem to come under that category.  It also
> leaves the issue open -- if someone comes up with a good solution in the
> future, we can always defined it.  But it really needed to be said.
>
> And I presume that this decision also holds for static members of
> exported template classes.  There is a difference.  The order in my
> example above could presumably be different between different
> compilation units, with no violation of the one definition rule.  If the
> variable definitions were exported, however, they would only occur in a
> single compilation unit.  Maybe when we get some experience with export,
> we can think of defining it there.  (But let's get the experience
> first.  I think I'm going to telecharge Comeau this week-end:-).  Even
> if I can only use it on personal experiments.)

Whether the templates are exported or not is a separate issue.   With export,
the template definitions appear in only one place, but that doesn't mean the
instantiations are located in that same one place.  Export is a source model,
not an instantiation model.  In the EDG compiler we support several
instantiation models, and export can be used with any of them.  Examples of
instantiation models are our prelinker-directed model, and the "instantiate
everywhere and let the linker weed out duplicates" model.

John Spicer
Edison Design Group

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@integrable-solutions.net (Gabriel Dos Reis)
Date: Wed, 30 Apr 2003 22:54:04 +0000 (UTC)
Raw View
kanze@gabi-soft.de (James Kanze) writes:

| Given the following code:
|
|     #include <iostream>
|     #include <ostream>
|
|     template< typename T >
|     struct D
|     {
|         D() : i( 1 ) {}
|         int i ;
|     } ;
|
|     template< typename T >
|     struct C
|     {
|         C() : i( myD.i ) {}
|         static D<T> myD ;
|         static C<T> instance ;
|         int i ;
|     } ;
|
|     template< typename T >
|     D<T> C<T>::myD ;
|
|     template< typename T >
|     C<T> C<T>::instance ;
|
|     int
|     main()
|     {
|         std::cout << C<int>::instance.i << '\n' ;
|         return 0 ;
|     }
|
| What should the program output?
|
| According to my understanding of the order of initialization,
| C<int>::myD should be initialized before C<int>::instance, since both
| are defined in the same translation unit, and C<int>::myD is defined
| before C<int>::instance; this results in the output 1.

The order of initialization does not say much about templates.
However, it does say someting about initialization of objects, not
that of template definition.  I think that is a key point.

Definitions from templates happen as  results of instantiations.
And the order of instantiations can impact on the order of *effective*
definitions (yes, the standard does not use the term effective definition).

The reference to C<int>::instance, first, causes the implicit
instantiation of the  class template C<T> with T = int.
That implicit instantiation in turn requires (only) declarations of the
static data members

   (1) C<int>::myD
   (2) C<int>::instance

(1) only requires the implicit instantiation of D<T> with T=int.

So at that point, we have something like:

   struct D<int>;

   struct C<int>
   {
      C();                              // note C() is -not- defined
      static D<int> myD;
      static C<int> instance;
   }

Second, in main(), C<int>::instance is referenced in a way that requires
its definition.  Therefore, we get the following new picture:

   struct D<int>;

   struct C<int>
   {
      C();                              // note C() is -not- defined
      static D<int> myD;
      static C<int> instance;
   }

   C<int> C<int>::instance;

But then, we need now to construct dynamically C<int>::instance, which
require the definition of the default construction.  Only that point,
the  default constructor is defined, so we get:

   struct D<int>;

   struct C<int>
   {
      C();                              // note C() is -not- defined
      static D<int> myD;
      static C<int> instance;
   }

   C<int> C<int>::instance;

   struct D<int>
   {
      D();
      int i;
   };

   inline
   C<int>::C() : i( myD.i ) {}

Note the definition order.  Now, C<int>::myD is referenced in a
context that needs its definition, as a consequence of initializing
C<int>::instance, again that definition is implicitly generated, but
then that (effective) definition  comes after that of
C<int>::instance.  In the end, we've got  something like

   struct D<int>;

   struct C<int>
   {
      C();                              // note C() is -not- defined
      static D<int> myD;
      static C<int> instance;
   }

   C<int> C<int>::instance;

   struct D<int>
   {
      D();
      int i;
   }

   inline
   C<int>::C() : i( myD.i ) {}

   D<int> C<int>::myD;

   inline
   D<int>::D() : i( 1 ) {}


That is how I read the very paragraph 14.7.1/1:

  Unless a class template specialization has been explicitly
  instantiated (14.7.2) or explicitly specialized (14.7.3), the class
  template specialization is implicitly instantiated when the
  specialization is referenced in a context that requires a
  completely-defined object type or when the completeness of the class
  type affects the semantics of the program. The implicit
  instantiation of a class template specialization causes the implicit
  instantiation of the declarations, but not of the definitions or
  default arguments, of the class member func-tions, member classes,
  static data members and member templates; and it causes the implicit
  instantiation of the definitions of member anonymous unions. Unless
  a member of a class template or a member tem-plate has been
  explicitly instantiated or explicitly specialized, the
  specialization of the member is implicitly instantiated when the
  specialization is referenced in a context that requires the member
  definition to exist; *in particular, the initialization (and any
  associated side-effects) of a static data member does not occur
  unless the static data member is itself used in a way that requires
  the definition of the static data member to exist*.

--
Gabriel Dos Reis, gdr@integrable-solutions.net

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jhs@edg.com ("John H. Spicer")
Date: Wed, 30 Apr 2003 22:56:10 +0000 (UTC)
Raw View

James Kanze wrote:
> Given the following code:
>
>     #include <iostream>
>     #include <ostream>
>
>     template< typename T >
>     struct D
>     {
>         D() : i( 1 ) {}
>         int i ;
>     } ;
>
>     template< typename T >
>     struct C
>     {
>         C() : i( myD.i ) {}
>         static D<T> myD ;
>         static C<T> instance ;
>         int i ;
>     } ;
>
>     template< typename T >
>     D<T> C<T>::myD ;
>
>     template< typename T >
>     C<T> C<T>::instance ;
>
>     int
>     main()
>     {
>         std::cout << C<int>::instance.i << '\n' ;
>         return 0 ;
>     }
>
> What should the program output?
>
> According to my understanding of the order of initialization,
> C<int>::myD should be initialized before C<int>::instance, since both
> are defined in the same translation unit, and C<int>::myD is defined
> before C<int>::instance; this results in the output 1.  Both g++ (3.2.2)
> and Sun CC (5.1) initialize C<int>::instance first, however, which
> results in the output 0 -- from discussions in fr.comp.lang.c++, I
> gather that other compilers have the same problem.

This was clarified by core issue #270, which was adopted in April of 2002, but
is not part of the TC that was just issued.  It clarifies that the order of
initialization of template static data members is unspecified both relative to
other template static data members and to other objects of static storage duration.

John Spicer
Edison Design Group

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: Wed, 30 Apr 2003 15:51:26 +0000 (UTC)
Raw View
Given the following code:

    #include <iostream>
    #include <ostream>

    template< typename T >
    struct D
    {
        D() : i( 1 ) {}
        int i ;
    } ;

    template< typename T >
    struct C
    {
        C() : i( myD.i ) {}
        static D<T> myD ;
        static C<T> instance ;
        int i ;
    } ;

    template< typename T >
    D<T> C<T>::myD ;

    template< typename T >
    C<T> C<T>::instance ;

    int
    main()
    {
        std::cout << C<int>::instance.i << '\n' ;
        return 0 ;
    }

What should the program output?

According to my understanding of the order of initialization,
C<int>::myD should be initialized before C<int>::instance, since both
are defined in the same translation unit, and C<int>::myD is defined
before C<int>::instance; this results in the output 1.  Both g++ (3.2.2)
and Sun CC (5.1) initialize C<int>::instance first, however, which
results in the output 0 -- from discussions in fr.comp.lang.c++, I
gather that other compilers have the same problem.

--
James Kanze             GABI Software             mailto:kanze@gabi-soft.fr
Conseils en informatique orient   e objet/
                           Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, T   l. : +33 (0)1 30 23 45 16

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: v.Abazarov@attAbi.com ("Victor Bazarov")
Date: Wed, 30 Apr 2003 17:36:17 +0000 (UTC)
Raw View
"James Kanze" <kanze@gabi-soft.de> wrote...
> Given the following code:
>
>     #include <iostream>
>     #include <ostream>
>
>     template< typename T >
>     struct D
>     {
>         D() : i( 1 ) {}
>         int i ;
>     } ;
>
>     template< typename T >
>     struct C
>     {
>         C() : i( myD.i ) {}
>         static D<T> myD ;
>         static C<T> instance ;
>         int i ;
>     } ;
>
>     template< typename T >
>     D<T> C<T>::myD ;
>
>     template< typename T >
>     C<T> C<T>::instance ;
>
>     int
>     main()
>     {
>         std::cout << C<int>::instance.i << '\n' ;
>         return 0 ;
>     }
>
> What should the program output?
>
> According to my understanding of the order of initialization,
> C<int>::myD should be initialized before C<int>::instance, since both
> are defined in the same translation unit, and C<int>::myD is defined
> before C<int>::instance; this results in the output 1.  Both g++ (3.2.2)
> and Sun CC (5.1) initialize C<int>::instance first, however, which
> results in the output 0 -- from discussions in fr.comp.lang.c++, I
> gather that other compilers have the same problem.


I am not sure you should call it "a problem".  The order of
template-declarations of the static data members of those
templates has no bearing on the order of their instantiation (or
even on the instantiation itself).

Read 14.6.4.1/1.  The instantiation of C<int>::myD happens not
by itself, but implicitly due to the initialisation of the object
C<int>::instance.  The point of instantiation of 'myD' "is the
point of instantiation of the enclosing specialization" (in your
case, the point of instantiation of the C<T> constructor), which
is _after_ C<int>::instance.  And it is not governed by the order
of template-declarations in the namespace scope.

So, the instantiation happens in the following order:

    -  C<int>::instance (explicit instantiation from the cout
       expression)
    -  C<int>::C (implicitly, to construct the 'instance')
    -  C<int>::myD (implicitly, because the constructor uses it)
    -  D<int>::D (implicitly, to construct the 'myD')

At least that's how I read it.

Victor
--
Please remove capital A's from my address when replying by mail


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]