1

I understand that if you attempt to split a templated class in a .h interface and a .cpp implementation, you get a linker error. The reason for this as mentioned in a popular post is "If the implementations were not in the header, they wouldn't be accessible, and therefore the compiler wouldn't be able to instantiate the template."

What I dont understand is that if the implementations inside a .cpp file are inaccessible in case of templated classes, what makes them accessible for non templated or just regular classes. How come we are able to split the interface and implementation for normal classes over a .h and .cpp file without getting a linker error?

Test.h

template<typename TypeOne>
TypeOne ProcessVal(TypeOne val);

Test.cpp

template<typename TypeOne>
TypeOne ProcessVal(TypeOne val)
{
    // Process it here.
    return val;
}

Main.cpp

void main()
{
    int a, b;
    b = ProcessVal(a);
}

This code gives linker error. A similar splitting of non templated classes does not give Linker error. I could post the code, but you get the idea.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
The Vivandiere
  • 3,059
  • 3
  • 28
  • 50
  • http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – xiaofeng.li Jan 04 '15 at 01:43
  • 1
    @infgeoax, I know, that's the article I quoted from. My question is not, Why must we not seperate the interface and implemntation for templated classes, rather, it is, what allows us to seperate these for non templated classes. – The Vivandiere Jan 04 '15 at 01:45
  • Template definition does not generate any output until you provide template arguments. Nothing is added to compilation unit, hence linker error. Non-templated function is compiled into the binary form and that's why linker sees them. – mip Jan 04 '15 at 02:15
  • 1
    @0x499P: You're doing it again! Bad dupe. – Lightness Races in Orbit Jan 04 '15 at 02:21

4 Answers4

4

In case of plain function, compiler generates code straightaway and adds generated code to compilation unit.

Test.cpp

int ProcessVal(int val)
{
    // Process it here.
    return val;
}

In case of the above code all the necessary information is known and C++ code of the function ProcessVal can be translated into machine instructions. As a result, object file (probably called Test.o) will contain ProcessVal symbol + corresponding code and linker can refer to it (to generate calls or to perform inlining).

On the other hand this piece of code:

Test.cpp

template<typename TypeOne>
TypeOne ProcessVal(TypeOne val)
{
    // Process it here.
    return val;
}

does not provide any output to compilation unit. Object file of this compilation unit (Test.o) will not contain any code for ProcessVal() function, because compiler does not know of what type TypeOne argument is going to be. You have to instantiate template to get its binary form and only this can be added to resulting binary.

mip
  • 8,355
  • 6
  • 53
  • 72
1

When you have a template definition, nothing is added to the compilation unit, because the template argument could be many things, so you can't know from compile time what class to create, as stated in this answer.

With the non-templated case, you know what you have inside your class, you don't have to wait for a template argument to be given in order to really generate the actual class, thus the linker can see them (since they are compiled into the binary as doc's post puts it).

Community
  • 1
  • 1
gsamaras
  • 71,951
  • 46
  • 188
  • 305
0

Basically, this goes back to the old C language. The .h files were intended to be done with the C preprocessor, and were literally textually included into the C source by the preprocessor. So if you had foo.h:

int i = 0;

and foo.c:

#include "foo.h"
int main(){ printf("%d\n", i);}

when the preprocessor was done, the compiler actually saw:

int i = 0;
int main(){ printf("%d\n", i);}

as the source file. There was no chance for a linker error, because the linker was never involved -- you just compiled one C file.

While the semantics of templates are a little more complicated now, the programming model is still the same: your .h file includes program text that is introduced to the program lexically, before actual final parsing and compilation takes place.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
0

If you actually do want to have the implementation of a template function or a class in a separate C++ file, you can explicitly instantiate it for a certain type. For instance, in your particular example if you add this line to test.cpp, your code will successfully link

template int ProcessVal<int>(int val);
Ishamael
  • 12,583
  • 4
  • 34
  • 52