Base template class symbols failing to link.

W

willo

All,

I'm having problems getting base-class template symbols to link
correctly.

My unit-test files are included below. I defined a templated Base-
Class 'A', and a templated Derived-Class 'B', only defining the
constructor and destructor.

I'm using 'g++-4.2', and get errors like:
willo:~/tmp$ g++ main.o B.o A.o -o main
B.o: In function `B<int>::B()':
B.cpp:(.text._ZN1BIiEC1Ev[B<int>::B()]+0x11): undefined reference to
`A<int>::A()'
B.o: In function `B<int>::~B()':
B.cpp:(.text._ZN1BIiED1Ev[B<int>::~B()]+0x11): undefined reference to
`A<int>::~A()'

This is despite the fact that I'm linking in another object file that
defines these symbols:
willo:~/tmp/$ nm --demangle A.o
0000000000000000 t instantiate_templated_class()
0000000000000000 W A<int>::A()
0000000000000000 W A<int>::~A()
U __gxx_personality_v0

Interestingly, if I remove the template parameter from Class A and B,
this error does not occur.

So, my question is, what am I doing wrong, or is what I'm trying to do
possible?

-- Charles Wilcox

willo:~/tmp$ cat A.h
#ifndef A_HEADER
#define A_HEADER

template< typename T >
class A
{
public: // methods
A();

~A();
};

#endif // ifndef A_HEADER

willo:~/tmp$ cat A.cpp
#include "A.h"

template< typename T >
A< T >::A() {}

template< typename T >
A< T >::~A() {}

static void instantiate_templated_class()
{
A< int > a;
}

willo:~/tmp$ cat B.h
#ifndef B_HEADER
#define B_HEADER

#include "A.h"

template< typename T >
class B : public A< T >
{
public: // methods
B();

~B();
};

#endif // ifndef B_HEADER

willo:~/tmp$ cat B.cpp
#include "B.h"

template< typename T >
B< T >::B() {}

template< typename T >
B< T >::~B() {}

static void instantiate_templated_class()
{
B< int > b;
}

willo:~/tmp$ cat main.cpp
#include "B.h"

int main( int argc, char* argv )
{
B< int > b;

return 0;
}
 
W

willo

http://www.parashift.com/c++-faq-lite/templates.html

read about linking errors, separating templates into headers-sources,
and the rest of course :)

Leclerc,

I've reviewed the Parashift info regarding templates and header / body
separation, and none of the information helps.

To re-iterate, I'm compiling each .cpp file just fine. I believe I've
separated the the .h and .cpp parts correctly.

This guide says nothing about linking templated base / derived
classes.

It's linking that has the problem. This is unexpected, as one of the
input compilation unit's defines the symbols that it complains about
not finding.

willo:~/tmp$ make
g++ -c -o main.o main.cpp
g++ -c -o B.o B.cpp
g++ -c -o A.o A.cpp
g++ main.o B.o A.o -o main
B.o: In function `B<int>::B()':
B.cpp:(.text._ZN1BIiEC1Ev[B<int>::B()]+0x11): undefined reference to
`A<int>::A()'
B.o: In function `B<int>::~B()':
B.cpp:(.text._ZN1BIiED1Ev[B<int>::~B()]+0x11): undefined reference to
`A<int>::~A()'
collect2: ld returned 1 exit status
make: *** [main] Error 1
willo:~/tmp/$ nm --demangle A.o
0000000000000000 t instantiate_templated_class()
0000000000000000 W A<int>::A()
0000000000000000 W A<int>::~A()
U __gxx_personality_v0
willo:~/tmp/$ nm --demangle B.o
0000000000000000 t instantiate_templated_class()
U A<int>::A()
U A<int>::~A()
0000000000000000 W B<int>::B()
0000000000000000 W B<int>::~B()
U __gxx_personality_v0

What is preventing the symbols for A in A.o from being used at link
time?

I could instantiate the A<int> symbols in B.o, but then I'd have
duplicate symbols, which can cause other linking errors in future
usage.

-- Charles Wilcox
 
N

Noah Roberts

Leclerc,

I've reviewed the Parashift info regarding templates and header / body
separation, and none of the information helps.

To re-iterate, I'm compiling each .cpp file just fine. I believe I've
separated the the .h and .cpp parts correctly.

You haven't. You've not given the compiler the information it needs to
instantiate the template's functions in B.cpp and main.cpp. Move your
template's function definitions to the header file and get rid of both
A.cpp and B.cpp completely.
This guide says nothing about linking templated base / derived
classes.

It's linking that has the problem. This is unexpected, as one of the
input compilation unit's defines the symbols that it complains about
not finding.

Of course it's linking that's the problem.
I could instantiate the A<int> symbols in B.o, but then I'd have
duplicate symbols, which can cause other linking errors in future
usage.

B.o has no knowledge of there being an instantiation of A<int> anyway.
It's going to try to build its own and since you've not given it the
necessary knowledge to do so, it won't be able to.
 
W

willo

Try re-reading questions 35.12 and 35.13, as they directly address your problem:

http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12

I just got help from Marshall, and have resolved this.

Actually, section 35.13 has the answer, although the example is only
for a template-function.

In my posted sample-code, I used a static function
"instantiate_templated_class" per .cpp file to instantiate the
templated versions I wanted said:
in B.cpp. I expected this to create the symbols needed in other
compilation-units.

However, that didn't work, and is not the way to do it. I should have
done:
template class A< int >
in A.cpp and:
template class B< int >
in B.cpp.

I had tried to do this before my posting, but I must have gotten the
syntax incorrect.

Anyway, thanks to all here and Marshall Cline for directing me to the
solution.

-- Charles Wilcox
 

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

No members online now.

Forum statistics

Threads
473,955
Messages
2,570,117
Members
46,705
Latest member
v_darius

Latest Threads

Top