Help with template friend and ostream, I think I am close

Discussion in 'C++' started by truce, Jan 13, 2006.

  1. truce

    truce Guest

    I searched but couldn't find anything _quite_ like this. I have some
    code I inherited that needs some work. Basically I have a template
    that is instantiated in the c++ code and so only the headers are
    distributed. That works great, the only problem is that I cant get
    the friend ostream inserter operator to work correctly. Basically
    it never is instantiated so it never shows up in the library. Here is
    a (close to) minimum example demonstrating the problem. I want
    to be able to do this without having all the code in the header since
    I know what instances I will need. Thanks in advance -- I believe
    I am close on this, but just can't quite get it.

    // Foo.hh
    using namespace::std;
    #include <iostream>

    template<int> class Foo;
    template<int mp>
    std::eek:stream & operator<< (std::eek:stream&, const Foo<mp> &);

    template<int mp>
    class Foo {
    public:
    char x[mp];
    Foo();
    friend std::eek:stream & operator<< <>(std::eek:stream&,const Foo<mp> &);
    };

    // end of Foo.hh

    // Foo.cc

    #include "Foo.hh"

    template<int mp>
    Foo<mp>::Foo()
    {
    int i;
    for (i=0;i<mp;i++);
    x = i;
    }

    template<int mp>
    std::eek:stream & operator<< (std::eek:stream&, const Foo<mp> &)
    {
    cout << "Nothing" << endl;
    }

    template class Foo<2>;

    // end of Foo.cc


    If I try to link this code when trying to use cout with an instance of
    Foo<2>:

    /tmp/test/Main.cc:8: undefined reference to `std::basic_ostream<char,
    std::char_traits<char> >& operator<< <(int)2>(std::basic_ostream<char,
    std::char_traits<char> >&, Foo<(int)2> const&)'

    And to confirm an nm on the object file Foo.o gives me:

    nm --demangle Foo.o
    00000054 t global constructors keyed to _ZN3FooILi2EEC1EvFoo.ccAPePOb
    00000000 t __static_initialization_and_destruction_0(int, int)
    00000000 W Foo<2>::Foo()
    00000000 W Foo<2>::Foo()
    U std::ios_base::Init::Init()
    U std::ios_base::Init::~Init()
    00000000 b std::__ioinit
    U __cxa_atexit
    U __dso_handle
    U __gxx_personality_v0
    00000040 t __tcf_0
     
    truce, Jan 13, 2006
    #1
    1. Advertising

  2. truce

    Earl Purple Guest

    The friend part is done correctly, the error is in here:

    truce wrote:
    >. Basically I have a template
    > that is instantiated in the c++ code and so only the headers are
    > distributed.


    Unless you and everyone you distribute to uses a compiler that can
    "export" templates, you cannot do that.

    And then you'd have to use the export keyword.
     
    Earl Purple, Jan 13, 2006
    #2
    1. Advertising

  3. truce wrote:
    > I searched but couldn't find anything _quite_ like this. I have some
    > code I inherited that needs some work. Basically I have a template
    > that is instantiated in the c++ code and so only the headers are
    > distributed. That works great, the only problem is that I cant get
    > the friend ostream inserter operator to work correctly.


    The friendship of the output operator is not related to your problem.

    > Basically
    > it never is instantiated so it never shows up in the library. Here is
    > a (close to) minimum example demonstrating the problem. I want
    > to be able to do this without having all the code in the header since
    > I know what instances I will need. Thanks in advance -- I believe
    > I am close on this, but just can't quite get it.

    [snip]

    If you are really sure you know all instantiations of Foo<>:
    be sure to call all related functions in foo.cc.

    Regards, Stephan
     
    =?iso-8859-1?q?Stephan_Br=F6nnimann?=, Jan 13, 2006
    #3
  4. truce

    truce Guest

    Re: Help with template friend and ostream g++, I think I am close

    "Stephan Brönnimann" <> wrote in message
    news:...
    > truce wrote:
    >
    >> Basically
    >> it never is instantiated so it never shows up in the library. Here is
    >> a (close to) minimum example demonstrating the problem. I want
    >> to be able to do this without having all the code in the header since
    >> I know what instances I will need. Thanks in advance -- I believe
    >> I am close on this, but just can't quite get it.

    > [snip]
    >
    > If you are really sure you know all instantiations of Foo<>:
    > be sure to call all related functions in foo.cc.


    This is the part that I dont understand. I dont know how to force
    the operator function. I do know how to force the template though.

    In foo.cc instantiate the objects for Foo of any type that I will ever use.
    This makes g++ generate all of the code in the template for any
    instances of Foo<2>. When compiled with the -fno-implicit-templates
    flag, the code is not needed in the header file. So I can write another
    piece of code, say main.cc such as this and link successfully even though
    at the time of compilation, it does not generate the code. It is already
    in Foo.o.

    #include "Foo.hh"
    int main(void) {
    Foo<2> xyz;
    ....
    }

    But clearly, this usage doesn't force the friend function to get
    instantiated that is why it does not link successfully. That is what I am
    trying to force. In the same way that template class Foo<2> forces the
    compiler to include all the code for the class, I want to force the friend
    function to be compiled as well.

    I did not get the other posters mention of the export keyword. But I
    distribute the library, headers, Makefile, and the cross compiler as a
    toolkit so I do know what they are using.
     
    truce, Jan 13, 2006
    #4
  5. Re: Help with template friend and ostream g++, I think I am close

    truce wrote:
    >
    > This is the part that I dont understand. I dont know how to force
    > the operator function. I do know how to force the template though.
    >
    > In foo.cc instantiate the objects for Foo of any type that I will ever use.
    > This makes g++ generate all of the code in the template for any
    > instances of Foo<2>. When compiled with the -fno-implicit-templates
    > flag, the code is not needed in the header file. So I can write another
    > piece of code, say main.cc such as this and link successfully even though
    > at the time of compilation, it does not generate the code. It is already
    > in Foo.o.

    [OT]
    Really?
    The option -fno-implicit-templates is specific to g++
    as well as its effects (I don't read the man page your way).
    Just for fun: compile foo.cc with g++-3.3 and g++4.0, compare the
    output.

    By this your problem gets compiler (and most probaly version) specific:
    How do I explictly instantiate a function template?
    [/OT]

    > #include "Foo.hh"
    > int main(void) {
    > Foo<2> xyz;
    > ....
    > }
    >
    > But clearly, this usage doesn't force the friend function to get
    > instantiated that is why it does not link successfully. That is what I am
    > trying to force. In the same way that template class Foo<2> forces the
    > compiler to include all the code for the class, I want to force the friend
    > function to be compiled as well.
    >
    > I did not get the other posters mention of the export keyword. But I
    > distribute the library, headers, Makefile, and the cross compiler as a
    > toolkit so I do know what they are using.


    Regards, Stephan
     
    =?iso-8859-1?q?Stephan_Br=F6nnimann?=, Jan 13, 2006
    #5
  6. truce

    truce Guest

    Re: Help with template friend and ostream g++, I think I am close

    "Stephan Brönnimann" <> wrote in message
    news:...
    >
    > [OT]
    > Really?
    > The option -fno-implicit-templates is specific to g++
    > as well as its effects (I don't read the man page your way).
    > Just for fun: compile foo.cc with g++-3.3 and g++4.0, compare the
    > output.
    >


    Tried your test. g++ 4.0.2, 3.3.5, and 3.4.4 all did
    the *exact* same thing and worked correctly.
    All three allowed me to compile the implementation
    file and link against my main object.

    Further, I figured out how to do it .... for the benefit of
    those who run across the same opportunity and want to
    distribute headers + a library using templates.

    // At the bottom of Foo.cc
    // create the code for the template
    template class Foo<2>;
    // create the code for the operator
    template ostream& operator << (ostream&, const Foo<2>&);
     
    truce, Jan 14, 2006
    #6
    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.

Share This Page