template implementation not seen by the compiler

C

Christof Warlich

Hi,

consider this:

template<typename T> class X {
public:
void doSomething(T t);
};
int main(void) {
X<int> x;
x.doSomething(4);
return 0;
}

It compiles fine but the linker is missing the implementation of
doSomething().

Why may it ever make sense that the compilation of this works fine? The
compiler already _knows_ that it could not instantiate doSomething() for
type int since it has not seen the (template) implementation of
doSomething(). Thus, linking will _always_ fail. Or do I miss a way to
pass the doSomething() implementation for a specific type to the linker
from another object file?

Thanks for any help,

Christof
 
R

Rolf Magnus

Christof said:
Hi,

consider this:

template<typename T> class X {
public:
void doSomething(T t);
};
int main(void) {
X<int> x;
x.doSomething(4);
return 0;
}

It compiles fine but the linker is missing the implementation of
doSomething().

Why may it ever make sense that the compilation of this works fine? The
compiler already _knows_ that it could not instantiate doSomething() for
type int since it has not seen the (template) implementation of
doSomething().

It might not need to.
Thus, linking will _always_ fail.

No. There could be another translation unit that defines doSomething() and
also instantiates the template for int. Then there would be an
implementation, but only the linker could find it.
 
C

Christof Warlich

Rolf said:
No. There could be another translation unit that defines doSomething() and
also instantiates the template for int. Then there would be an
implementation, but only the linker could find it.

I was hoping to get exactly this answer :) as it makes sense and could
solve my design issue (see my post "virtual constructor ideom with
templates" above). But it unfortunately did not work: I tried the
following code, trying to translate it with

$ g++ -c main.cc
$ g++ -c implementation.cc
$ g++ main.o implementation.o -o main

but I still get the same error message from the linker. Any idea how
this can be made work?

Thanks,

Christof

// template.h
template<typename T> class X {
public:
void doSomething(T t);
};
// template.h ends

// main.cc
#include "template.h"
int main(void) {
X<int> x;
x.doSomething(4);
return 0;
}
// main.cc ends

// implementation.cc
#include "template.h"
template<typename T> void X<T>::doSomething(T t) {
// do something useful
}
X<int> dummy;
// implementation.cc ends
 
G

Greg

Christof said:
I was hoping to get exactly this answer :) as it makes sense and could
solve my design issue (see my post "virtual constructor ideom with
templates" above). But it unfortunately did not work: I tried the
following code, trying to translate it with

$ g++ -c main.cc
$ g++ -c implementation.cc
$ g++ main.o implementation.o -o main

but I still get the same error message from the linker. Any idea how
this can be made work?

Thanks,

Christof

// template.h
template<typename T> class X {
public:
void doSomething(T t);
};
// template.h ends

// main.cc
#include "template.h"
int main(void) {
X<int> x;
x.doSomething(4);
return 0;
}
// main.cc ends

// implementation.cc
#include "template.h"
template<typename T> void X<T>::doSomething(T t) {
// do something useful
}
X<int> dummy;
// implementation.cc ends

The definition of a template must be visible at the point it is needed
in a source file. In this case, the doSomething() method is needed in
main.cc, but its definition is not visible to main.cc. Instead
doSomething's definition is found in implementation.cc - a source file
which has no need for it.

In order to ensure that template definitions are available to the
source code files that need them, the easiest solution (at least in the
absence of template export support) is to place template definitions in
header files. Therefore moving doSomething()'s definition to, say,
template.h while having main.cc include template.h would be the most
straightforward way to fix this problem.

Greg
 
A

Alex Buell

It compiles fine but the linker is missing the implementation of
doSomething().

Why may it ever make sense that the compilation of this works fine?
The compiler already _knows_ that it could not instantiate doSomething
() for type int since it has not seen the (template) implementation
of doSomething(). Thus, linking will _always_ fail. Or do I miss a
way to pass the doSomething() implementation for a specific type to
the linker from another object file?

The compiler doesn't have to flag an error as the definition might be
in another file.
 
R

Rolf Magnus

Christof said:
I was hoping to get exactly this answer :) as it makes sense and could
solve my design issue (see my post "virtual constructor ideom with
templates" above). But it unfortunately did not work: I tried the
following code, trying to translate it with

$ g++ -c main.cc
$ g++ -c implementation.cc
$ g++ main.o implementation.o -o main

but I still get the same error message from the linker. Any idea how
this can be made work?

Thanks,

Christof

// template.h
template<typename T> class X {
public:
void doSomething(T t);
};
// template.h ends

// main.cc
#include "template.h"
int main(void) {
X<int> x;
x.doSomething(4);
return 0;
}
// main.cc ends

// implementation.cc
#include "template.h"
template<typename T> void X<T>::doSomething(T t) {
// do something useful
}
X<int> dummy;
// implementation.cc ends

That might be because doSomething() isn't called in implemetation.cc and so
it's never instantiated. Try to use explicit template instantiation instead
of a dummy variable:

template class X<int>;
 
C

Christof Warlich

Greg said:
The definition of a template must be visible at the point it is needed
in a source file. In this case, the doSomething() method is needed in
main.cc, but its definition is not visible to main.cc.
But that's my point: If the definition _has_ to be visible in main.cc,
why does only the linker and not already the compiler flag an error?
Instead
doSomething's definition is found in implementation.cc - a source file
which has no need for it.
It _has_ a need for it; this is why I put the line
X said:
In order to ensure that template definitions are available to the
source code files that need them, the easiest solution (at least in the
absence of template export support) is to place template definitions in
header files. Therefore moving doSomething()'s definition to, say,
template.h while having main.cc include template.h would be the most
straightforward way to fix this problem.
I know, but it would not solve my design goal to to keep the
implementation invisible to the user. :-(
 
C

Christof Warlich

Alex said:
The compiler doesn't have to flag an error as the definition might be
in another file.
That's what Rolf Magnus already suggested. But do you have an idea _how_
I could feed this information to the compiler from another file? This
would just solve the issue I'm currently concerned with.

Please look at my response to Rolf Magnus to see my (straight forward
but unsuccessful) attempt.

Thanks and regards,

Christof
 
C

Christof Warlich

That might be because doSomething() isn't called in implemetation.cc and so
it's never instantiated. Try to use explicit template instantiation instead
of a dummy variable:

template class X<int>;
Hey, that's doing the trick! You've probably saved me another sleepless
night, so thank's a lot for your help.

Regards,

Christof
 
G

Greg

Christof said:
But that's my point: If the definition _has_ to be visible in main.cc,
why does only the linker and not already the compiler flag an error?

A referenced template has to be visible in order to be instantiated -
and every referenced template must be instantiated in order for the
program to link.

Strictly speaking, a template class or function does not need to be
instantiated in the same translation unit that uses it - just as long
as the template is instantiated in at least one of the other
translation units that are linked together to produce the final
program.

But there are notable disadvantages if the template is not instantiated
in the source file the requires it. Consider:

* Added bookkeeping overhead
Instead of the compiler instantiating templates as they are needed, the
programmer has to assume the tedious responsibility of determining
which templates need to be instantiated and to maintain this list
during development.

* Potential code bloat
A programmer is likely to instantiate an entire class template for a
particular type instead of just the method or methods actually
referenced.

* Lost optimization opportunities
With the template definition not present at the point it is needed, the
compiler loses the ability to inline function calls or to perform any
other optimization with the template.at the translation unit level.

Greg
 

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
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top