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

T

truce

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
 
E

Earl Purple

The friend part is done correctly, the error is in here:
. 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.
 
?

=?iso-8859-1?q?Stephan_Br=F6nnimann?=

truce said:
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
 
T

truce

Stephan Brönnimann said:
truce said:
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.
 
?

=?iso-8859-1?q?Stephan_Br=F6nnimann?=

truce said:
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
 
T

truce

Stephan Brönnimann said:
[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>&);
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top