Template instantiation context

Discussion in 'C++' started by Juha Nieminen, Jul 18, 2009.

  1. Assume we have these three files:

    //--------------------------------------------------------------
    // foo.hh
    #include <iostream>

    template<typename T>
    void foo(T value)
    {
    static int s = 0;
    ++s;
    std::cout << "value:" << value << ", s:" << s
    << ", externalVar:" << externalVar << std::endl;
    }
    //--------------------------------------------------------------

    //--------------------------------------------------------------
    // bar.cc
    namespace { const int externalVar = 456; }
    #include "foo.hh"

    void bar()
    {
    std::cout << "In bar(): ";
    foo(200);
    }
    //--------------------------------------------------------------

    //--------------------------------------------------------------
    // test.cc
    namespace { const int externalVar = 123; }
    #include "foo.hh"

    void bar();

    int main()
    {
    std::cout << "In main(): ";
    foo(100);
    bar();
    }
    //--------------------------------------------------------------

    Now we compile test.cc and bar.cc into an executable program. What
    should be the output of this program?
     
    Juha Nieminen, Jul 18, 2009
    #1
    1. Advertising

  2. * Juha Nieminen:
    > Assume we have these three files:
    >
    > //--------------------------------------------------------------
    > // foo.hh
    > #include <iostream>
    >
    > template<typename T>
    > void foo(T value)
    > {
    > static int s = 0;
    > ++s;
    > std::cout << "value:" << value << ", s:" << s
    > << ", externalVar:" << externalVar << std::endl;
    > }
    > //--------------------------------------------------------------
    >
    > //--------------------------------------------------------------
    > // bar.cc
    > namespace { const int externalVar = 456; }
    > #include "foo.hh"
    >
    > void bar()
    > {
    > std::cout << "In bar(): ";
    > foo(200);
    > }
    > //--------------------------------------------------------------
    >
    > //--------------------------------------------------------------
    > // test.cc
    > namespace { const int externalVar = 123; }
    > #include "foo.hh"
    >
    > void bar();
    >
    > int main()
    > {
    > std::cout << "In main(): ";
    > foo(100);
    > bar();
    > }
    > //--------------------------------------------------------------
    >
    > Now we compile test.cc and bar.cc into an executable program. What
    > should be the output of this program?


    It's UB.

    Btw., please don't formulate real questions so that they sound like homework.

    If this question had any other answer than UB I would have believed it to be
    homework.


    Cheers & hth.,


    - Alf
     
    Alf P. Steinbach, Jul 18, 2009
    #2
    1. Advertising

  3. Alf P. Steinbach wrote:
    > Btw., please don't formulate real questions so that they sound like
    > homework.


    I don't know if you have seen me posting in this group before, but if
    you have, you'd probably know that I have been in the business for long
    enough that doing homework is way in the past for me by now... :)

    This was a genuine question because I'm not completely sure how
    template functions should work with respect to:

    a) local static variables
    b) variables in the outer scope

    My best guess is that one type generates one single function (which,
    if duplicated in more than one object file, gets merged by the linker),
    in which case the static variable should be unique even when the
    function is instantiated in more than one compilation unit. But that
    raises the question what happens when the context is different (in this
    case, when the variable name in the outer scope refers to different
    variables in the two compilation units).

    Rather than writing an essay as my question, I kept the post short and
    simple.
     
    Juha Nieminen, Jul 18, 2009
    #3
  4. Juha Nieminen

    Pavel Guest

    Alf P. Steinbach wrote:
    > * Juha Nieminen:
    >> Assume we have these three files:
    >>
    >> //--------------------------------------------------------------
    >> // foo.hh
    >> #include <iostream>
    >>
    >> template<typename T>
    >> void foo(T value)
    >> {
    >> static int s = 0;
    >> ++s;
    >> std::cout << "value:" << value << ", s:" << s
    >> << ", externalVar:" << externalVar << std::endl;
    >> }
    >> //--------------------------------------------------------------
    >>
    >> //--------------------------------------------------------------
    >> // bar.cc
    >> namespace { const int externalVar = 456; }
    >> #include "foo.hh"
    >>
    >> void bar()
    >> {
    >> std::cout << "In bar(): ";
    >> foo(200);
    >> }
    >> //--------------------------------------------------------------
    >>
    >> //--------------------------------------------------------------
    >> // test.cc
    >> namespace { const int externalVar = 123; }
    >> #include "foo.hh"
    >>
    >> void bar();
    >>
    >> int main()
    >> {
    >> std::cout << "In main(): ";
    >> foo(100);
    >> bar();
    >> }
    >> //--------------------------------------------------------------
    >>
    >> Now we compile test.cc and bar.cc into an executable program. What
    >> should be the output of this program?

    >
    > It's UB.
    >
    > Btw., please don't formulate real questions so that they sound like
    > homework.
    >
    > If this question had any other answer than UB I would have believed it
    > to be homework.

    Why? It could be an interview questions but then OP would not be able to
    use Internet. I can't see how it could be HW. It looks like a fully
    compliant question to me.

    -Pavel
     
    Pavel, Jul 18, 2009
    #4
  5. Juha Nieminen

    Bo Persson Guest

    Juha Nieminen wrote:
    > Alf P. Steinbach wrote:
    >> Btw., please don't formulate real questions so that they sound like
    >> homework.

    >
    > I don't know if you have seen me posting in this group before, but
    > if you have, you'd probably know that I have been in the business
    > for long enough that doing homework is way in the past for me by
    > now... :)
    >
    > This was a genuine question because I'm not completely sure how
    > template functions should work with respect to:
    >
    > a) local static variables
    > b) variables in the outer scope
    >
    > My best guess is that one type generates one single function
    > (which, if duplicated in more than one object file, gets merged by
    > the linker), in which case the static variable should be unique
    > even when the function is instantiated in more than one compilation
    > unit. But that raises the question what happens when the context is
    > different (in this case, when the variable name in the outer scope
    > refers to different variables in the two compilation units).
    >
    > Rather than writing an essay as my question, I kept the post short
    > and simple.


    By having different meanings for the for the name in the outer scope,
    you have violated the One Definition Rule.

    A template can be defined in several translation units, but the
    meaning must be the same. Here it is not.


    Bo Persson
     
    Bo Persson, Jul 18, 2009
    #5
  6. * Pavel:
    > Alf P. Steinbach wrote:
    >> * Juha Nieminen:
    >>> Assume we have these three files:
    >>>
    >>> //--------------------------------------------------------------
    >>> // foo.hh
    >>> #include <iostream>
    >>>
    >>> template<typename T>
    >>> void foo(T value)
    >>> {
    >>> static int s = 0;
    >>> ++s;
    >>> std::cout << "value:" << value << ", s:" << s
    >>> << ", externalVar:" << externalVar << std::endl;
    >>> }
    >>> //--------------------------------------------------------------
    >>>
    >>> //--------------------------------------------------------------
    >>> // bar.cc
    >>> namespace { const int externalVar = 456; }
    >>> #include "foo.hh"
    >>>
    >>> void bar()
    >>> {
    >>> std::cout << "In bar(): ";
    >>> foo(200);
    >>> }
    >>> //--------------------------------------------------------------
    >>>
    >>> //--------------------------------------------------------------
    >>> // test.cc
    >>> namespace { const int externalVar = 123; }
    >>> #include "foo.hh"
    >>>
    >>> void bar();
    >>>
    >>> int main()
    >>> {
    >>> std::cout << "In main(): ";
    >>> foo(100);
    >>> bar();
    >>> }
    >>> //--------------------------------------------------------------
    >>>
    >>> Now we compile test.cc and bar.cc into an executable program. What
    >>> should be the output of this program?

    >>
    >> It's UB.
    >>
    >> Btw., please don't formulate real questions so that they sound like
    >> homework.
    >>
    >> If this question had any other answer than UB I would have believed it
    >> to be homework.

    > Why? It could be an interview questions but then OP would not be able to
    > use Internet. I can't see how it could be HW. It looks like a fully
    > compliant question to me.


    The "What should be the output of this program?" triggered my HW recognition
    meter. It is the form of the question, a code example followed by "what does
    this do?", which is characteristic of homework and almost never what the author
    of the code in question would ask. I ignored the HW meter needle's movement
    because if it was homework then there would be a definite answer, not UB. :)


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Jul 18, 2009
    #6
  7. g++ -Wall -g bar.cc test.cc produces:
    In main(): value:100, s:1, externalVar:456
    In bar(): value:200, s:2, externalVar:456
     
    Classic Wrinwright, Jul 19, 2009
    #7
  8. Juha Nieminen

    James Kanze Guest

    On Jul 18, 7:43 pm, "Alf P. Steinbach" <> wrote:
    > * Juha Nieminen:


    [...]
    > > Now we compile test.cc and bar.cc into an executable
    > > program. What should be the output of this program?


    > It's UB.


    > Btw., please don't formulate real questions so that they sound
    > like homework.


    > If this question had any other answer than UB I would have
    > believed it to be homework.


    I'd say that the author would have been enough; Juha's not
    exactly new to this group. And I've not seen much homework
    which involves separate compilation (or other things essential
    when writing real code).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jul 19, 2009
    #8
  9. Classic Wrinwright wrote:
    > g++ -Wall -g bar.cc test.cc produces:
    > In main(): value:100, s:1, externalVar:456
    > In bar(): value:200, s:2, externalVar:456


    Well, I didn't ask what gcc will print (because I can test that
    myself). I asked what *should* be printed.

    (OTOH, if the value printed for externalVar is indeed UB, then any
    value would be as valid as anything else, I suppose.)
     
    Juha Nieminen, Jul 19, 2009
    #9
  10. Juha Nieminen

    James Kanze Guest

    On Jul 19, 2:00 pm, Juha Nieminen <> wrote:
    > Classic Wrinwright wrote:
    > > g++ -Wall -g bar.cc test.cc produces:
    > > In main(): value:100, s:1, externalVar:456
    > > In bar(): value:200, s:2, externalVar:456


    > Well, I didn't ask what gcc will print (because I can test
    > that myself).


    Actually, you can't very well, since g++ doesn't define it any
    more than the standard does. Thus (on my Linux box):

    $ g++ -std=c++98 -pedantic bar.cc test.cc
    $ a.out
    In main(): value:100, s:1, externalVar:456
    In bar(): value:200, s:2, externalVar:456
    $ g++ -std=c++98 test.cc bar.cc
    $ a.out
    In main(): value:100, s:1, externalVar:123
    In bar(): value:200, s:2, externalVar:123
    $ g++ -std=c++98 -pedantic -O bar.cc test.cc
    $ a.out
    In main(): value:100, s:1, externalVar:123
    In bar(): value:200, s:2, externalVar:456

    So there is no correct answer to what g++ will print. (Which is
    what undefined behavior is all about.)

    > I asked what *should* be printed.


    > (OTOH, if the value printed for externalVar is indeed UB, then
    > any value would be as valid as anything else, I suppose.)


    Anything the compiler does is valid. Including refusing to
    compile the code. (IMHO, it wouldn't be that difficult to
    detect the problem at link time, and generate an error message
    then.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jul 20, 2009
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Fernando Cuenca
    Replies:
    4
    Views:
    2,558
    Gianni Mariani
    Sep 6, 2004
  2. Thomas Maier-Komor
    Replies:
    6
    Views:
    660
    Thomas Maier-Komor
    May 19, 2005
  3. Replies:
    1
    Views:
    617
    Salt_Peter
    Dec 25, 2006
  4. Replies:
    4
    Views:
    353
  5. Ed
    Replies:
    1
    Views:
    359
Loading...

Share This Page