Re: Template & Friend

Discussion in 'C++' started by franky.backeljauw@ua.ac.be, Jun 25, 2003.

  1. Guest

    On Tue, 24 Jun 2003, tom_usenet wrote:

    > On Mon, 23 Jun 2003 01:08:32 +0200, wrote:
    >
    > >First of all, if one wants to have a library file with all implementations
    > >for the functions in it, you must explicitly instantiate the template
    > >specializations too. So first of all, I added
    > >
    > > template class tempo<int>;
    > >
    > >at the end of templates.h header file. Actually, it does not seem to make
    > >any difference whether you put it in the header file or in the source
    > >file, so I just added it to the header file, as I feel this is best - this
    > >way someone who looks at the header can see which specializations exist.

    >
    > You have to put it in the source file or otherwise, if two different
    > cpp files include the header, you will get a multiple definition
    > error. It is like a function definition - it must be defined only once
    > (the one definition rule or ODR).


    Well, I get your point, but it seems to work just fine when it is in the
    header too. I've made a second file just like test.cpp, called test2.cpp,
    both including templates.h, where main() is replaced by test() in
    test2.cpp, and I am calling this function in the main() from the test.cpp
    file. Now, compiling these to test.o and test2.o and linking them, this
    gives me an executable which is just increased by approximately the size
    of the test2.o (which contains only the test() function).

    Indeed, the size of this executable is a bit bigger than if I put these
    lines in the templates.cpp file - 18016 compared to 17968 for gcc - but I
    do not get multiple defintion errors. I do get these if I would put these
    lines in both templates.h and templates.cpp.

    > >Unfortunately, adding (again as you said)
    > >
    > > template<> void printValue<int>(tempo<int>);

    >
    > That is a declaration of an explicit specialization of printValue, for
    > int. You need a separate definition of printValue<int> (not just the T
    > version) for that to work - I don't think it is what you want, since
    > you don't want to do anything special with int, which is what
    > specialization is for.
    >
    > >gave me the same error message.

    >
    > Yes, if you have that (it is only a declaration of the
    > specialization), you also need to add the definition in templates.cpp.
    > e.g.
    >
    > template <> void printValue<int>(tempo<int>)
    > {
    > //whatever
    > }
    >
    > > template void printValue<int>(tempo<int>);

    >
    > That is an explicit instantiation of the int version of printValue.
    > The definition of printValue is required to do this, so you should put
    > it in the templates.cpp file after the definition of printValue, along
    > with any other instantiations you need.


    Indeed, that's why I replaced this by

    template void printValue<int>(tempo<int>);

    but WHAT I FORGOT TO SAY (sorry for that) was that I added this to
    templates.cpp, and not to templates.h (otherwise I got those even worse
    error messages) - Woohoo!

    > > template void printValue<int>(tempo<int>);

    >
    > That is an explicit instantiation of the int version of printValue.
    > The definition of printValue is required to do this, so you should put
    > it in the templates.cpp file after the definition of printValue, along
    > with any other instantiations you need.


    That's just what I did :) I don't need a different specialization of
    this function for int - the templated function will do just fine, but it
    just needs to be specialized for int. So I think there's no need to
    specify the template<> thing explicitly in the header (which is what you
    also said above).

    > ><code:templates.h>
    > >[..]
    > >template class tempo<int>;
    > >template class tempo<string>;
    > ></code:templates.h>

    >
    > The above two explicit instantiations should go into templates.cpp -
    > I'm surprised you don't get an error above getValue being undefined
    > when you try to compile test.cpp


    That is because I'm just compiling, not linking. The compiler sees that
    there is a templated class tempo for which it can replace T by int, so it
    will supposes (or expects) to find an implementation for the getValue()
    function in the end (that is, when linking).

    I would be getting this error when linking if I would not have put these
    explicit instantiations in neither templates.h nor templates.cpp, since
    then the linking process will not find the specializations - they must be
    in the library file at compile time, because the compiler cannot generate
    extra specializations since it does not know the implementations (it does
    not have the templates.cpp file).

    But if these two lines are in templates.h, the compiler will generate them
    when creating templates.o, as the templates.cpp file includes templates.h.

    > ><code:templates.cpp>
    > >[..]
    > >template void printValue<int>( tempo<int> );
    > >template void printValue<string>( tempo<string> );
    > ></code:templates.cpp>

    >
    > Right, that is the place for explicit instantiations, after the
    > definitions of the functions/class members in a .cpp file. Explicit
    > instantiations have to satisfy the ODR.


    But that does not seem to be the case for the explicit instantiations of
    the templated class itself, that is for

    template class tempo<int>;

    So what is the case for this then???

    > >But when I do
    > >
    > > CC -o test test.o templates.o
    > >
    > >it works fine. I don't know what causes this error to occur, but I've
    > >seen other people reporting the same sort of problems.

    >
    > Perhaps try using CC with the switches to make a static library. I
    > don't know CC though.


    That was indeed the problem - if I use

    CC -xar -o libtemplates.a templates.o

    instead of "ar" to create the library it works just fine. I found that
    when I executed "file libtemplates.a", this gave me the message

    current ar archive, not a dynamic executable or shared object

    so the file created with "ar" seems to be a valid library file too - so my
    guess is that CC puts something specific/extra into the library file, but
    I still have to check this one out to be sure.

    > You might want to get the book http://www.josuttis.com/tmplbook/. It
    > is the only book I know of that covers this stuff in detail (although
    > I haven't read it - I tend to use the C++ standard as a reference).


    I've checked the helpfile that came with this book, but I did not find any
    answers on this explicit topic of "templates, friends, and libraries".

    Thanks again.

    Regards,

    Franky Backeljauw
    University of Antwerp
    Department of Mathematics and Computer Science
    , Jun 25, 2003
    #1
    1. Advertising

  2. Guest

    On Wed, 25 Jun 2003, tom_usenet wrote:

    I'll just quote small parts here ...

    > I'll just quote the standard on this, and you can make up your own
    > mind:
    >
    > "No program shall explicitly instantiate any template more than once,
    > both explicitly instantiate and explicitly specialize a template, or
    > specialize a template more than once for a given set of
    > template­arguments.
    > An implementation is not required to diagnose a violation of this
    > rule."
    >
    > So your implementation isn't diagnosing it, as is permitted, but it
    > might cause some kind of problem in the future or on a different
    > compiler.


    So now we know that neither gcc, icc, nor CC diagnose this.

    > Right, with this implementation and this version, but there are
    > certainly valid implementations for which it won't work properly, so
    > you may as well do it right.


    > >But if these two lines are in templates.h, the compiler will generate them
    > >when creating templates.o, as the templates.cpp file includes templates.h.

    >
    > The problem is that it will also generate them when compiling
    > test.cpp, which you don't want (and is strictly speaking illegal), but
    > this won't happen if you put them in templates.cpp.


    You're right - I'll change this. But then I'll have to find another way
    to let the users know which specializations exist and which not.

    > That they should only be explicitly instantiated once, and that
    > violations of this are undefined behaviour that doesn't have to be
    > diagnosed. FWIW, if you add a static int variable to tempo, Comeau C++
    > will throw a linker error if you have the explicit instantiation in
    > both .cpp files. You get a different error depending on whether you
    > put the definition of the static (
    > template <class T>
    > int tempo<T>::i = 0;
    > ) in the header or in template.cpp. However, G++ still seemed to
    > compile it.


    I don't understand what you want to say here ... as far as I see it, there
    is only one file where the explicit instatiation of the static would go
    into, namely templates.cpp. This compiles just fine with both g++ and CC.

    > >so the file created with "ar" seems to be a valid library file too - so my
    > >guess is that CC puts something specific/extra into the library file, but
    > >I still have to check this one out to be sure.

    >
    > It might do something special with templates to allow multiple
    > (implicit) instantiations of the same template to be merged.
    >
    > With implicit instantiation, you can end up with the definition of a
    > template in multiple translation units, and different compilers do
    > different things. Comeau C++ carefully assigns each instantiation to a
    > particular translation unit, and only compiles it once. MSVC compiles
    > it in each translation unit, but then strips duplicates out during
    > linking. I think G++ can just leave all the duplicates in, but ensures
    > that all uses of the template end up resolving to the same
    > instantiation. This requires a bit of fiddling with the object files,
    > I imagine.


    I found the following information from the CC man pages:

    -xar Creates archive libraries.

    When building a C++ archive that uses templates,
    it is necessary in most cases to include in the
    archive those template functions that are instan-
    tiated in the template repository. Using this
    option automatically adds those templates to the
    archive as needed.

    Examples:

    The following command archives the template func-
    tions contained in the repository and the object
    files.

    % CC -xar -o libmain.a a.o b.o c.o

    Warnings:

    Do not add .o files from the template repository
    on the command line.

    Do not use the ar command directly for building
    archives. Use CC -xar to ensure that template
    instantiations are automatically included in the
    archive.

    This seems to indicate that the CC compiler does not generate any explicit
    specialization "implicitly", if you know what I'm saying, but defers this
    to either the linking phase or when we ask it to "explicitly" generate
    them so it can put them in a library file. I don't know what they mean
    with the "template repository" though.

    I guess the ar command just behaves differently, though I haven't been
    able yet to figure out how, especially on our topic of templates - and
    interacts differently with the linker ...

    I just did a test, compiling everything with the g++ compiler, but
    generating the library with the "CC -xar" command, and it gives no
    problems whatsoever. Only the size of the files differ:

    libtemplates.a using only CC : 26916
    libtemplates.a using g++ and ar : 7560
    libtemplates.a using g++ and "CC -xar" : 32028

    test using only CC : 36124
    test using g++ and ar : 12300
    test using g++ and "CC -xar" : 12300

    The last line shows the problem is with the ar command ... maybe one day
    I'll figure out what exactly the difference is.

    -- Regards,

    Franky Backeljauw
    University of Antwerp
    Department of Mathematics and Computer Science
    , Jun 26, 2003
    #2
    1. Advertising

  3. tom_usenet Guest

    On Fri, 27 Jun 2003 00:58:29 +0200, wrote:

    >> That they should only be explicitly instantiated once, and that
    >> violations of this are undefined behaviour that doesn't have to be
    >> diagnosed. FWIW, if you add a static int variable to tempo, Comeau C++
    >> will throw a linker error if you have the explicit instantiation in
    >> both .cpp files. You get a different error depending on whether you
    >> put the definition of the static (
    >> template <class T>
    >> int tempo<T>::i =3D 0;
    >> ) in the header or in template.cpp. However, G++ still seemed to
    >> compile it.

    >
    >I don't understand what you want to say here ... as far as I see it, there
    >is only one file where the explicit instatiation of the static would go
    >into, namely templates.cpp. This compiles just fine with both g++ and CC.


    The explicit instantion of tempo was in the header, so it is generated
    in both templates.cpp and test.cpp. GCC somehow copes with this, but
    Comeau C++ diagnoses the problem.

    All I'm saying is that it is non-standard to put the instantiations in
    the header (due to multiple definitions), and although the current
    versions of your current compilers with the current switches you are
    using don't complain due to how they happen to be implemented, others
    will, at least if tempo has any static variables added. So you may as
    well put instantiations where they belong.

    >I found the following information from the CC man pages:
    >
    > -xar Creates archive libraries.
    >
    > When building a C++ archive that uses templates,
    > it is necessary in most cases to include in the
    > archive those template functions that are instan-
    > tiated in the template repository. Using this
    > option automatically adds those templates to the
    > archive as needed.


    Right, it sounds like CC uses the "CFront" model of template
    instantiaion, rather than the "Borland" model. Check out this site for
    an explanation:

    http://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Template-Instantiation.html#Template Instantiation

    >This seems to indicate that the CC compiler does not generate any explicit
    >specialization "implicitly", if you know what I'm saying, but defers this
    >to either the linking phase or when we ask it to "explicitly" generate
    >them so it can put them in a library file. I don't know what they mean
    >with the "template repository" though.


    Yup, this seems to be the case. It maintains a list of required
    instantiations (in the "template repository", perhaps a .ti file) for
    each source file, and has a pre-linker that uses the linker to see
    which instantiations are missing, and then adds them to the
    repositories before compiling them into the .o files and finally
    linking.

    This is similar to the model used by Comeau C++, except that has a
    completely standard model that even supports the legendary "export"
    keyword.

    >I guess the ar command just behaves differently, though I haven't been
    >able yet to figure out how, especially on our topic of templates - and
    >interacts differently with the linker ...


    Using ar means that the pre-linker doesn't get invoked, so template
    instantiations aren't compiled in.

    >
    >I just did a test, compiling everything with the g++ compiler, but
    >generating the library with the "CC -xar" command, and it gives no
    >problems whatsoever. Only the size of the files differ:
    >
    > libtemplates.a using only CC : 26916
    > libtemplates.a using g++ and ar : 7560
    > libtemplates.a using g++ and "CC -xar" : 32028
    >
    > test using only CC : 36124
    > test using g++ and ar : 12300
    > test using g++ and "CC -xar" : 12300
    >
    >The last line shows the problem is with the ar command ... maybe one day
    >I'll figure out what exactly the difference is.


    The pre-link step. You might be able to get CC to do the prelinking
    step but not the final link, if you want to use ar for some reason.

    Tom
    tom_usenet, Jun 27, 2003
    #3
    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. Gianni Mariani
    Replies:
    1
    Views:
    345
    tom_usenet
    Sep 5, 2003
  2. Yueh-Wei Hu
    Replies:
    0
    Views:
    438
    Yueh-Wei Hu
    May 23, 2004
  3. Replies:
    2
    Views:
    466
    John Harrison
    Nov 9, 2005
  4. A L
    Replies:
    1
    Views:
    504
    Alf P. Steinbach /Usenet
    Aug 25, 2010
  5. Peter
    Replies:
    2
    Views:
    267
    Öö Tiib
    Jun 6, 2013
Loading...

Share This Page