Where to define template classes and functions?

I have a decent understanding of how templates work and what their purpose is, but I'm having trouble with putting the definition in the correct place (linker errors). I understand that the definition of a template function (or a member function of a template class) must be available in every translation unit it is used in. So, what is the de facto way to accomplish that?

Where to define:
1. Should the definition be placed in a .h or a .cpp file (and that .cpp file #include d)? That is to say, should the definition of a template class/function result in its own .o file?
2. For classes, should member function definitions be placed in the same .h file where the class itself is defined? (Note: I've run into circular dependency issues with #include , resulting in 'incomplete type' errors when using this pattern.)
3. Should the definition of a template class/function be #include d in its own .h file (e.g. 'ClassName_impl.h'), and that .h file #include d in translation units where the definition is needed?
4. Should each function have its own definition file (e.g. ClassName::functionName.cpp)?

Where to #include :
5. Should the definition be included in the declaration header file?
5.1. What if I am inheriting from a template class (e.g. class Derived: public Base<Type> {...};
6. Should the definition be included in the .cpp file where it is used?
Last edited on
You have to have the function definition in the same file as the declaration. The compiler creates the non-template function as needed, so there is no way to have an object file ( .o ).

Basically, it's all got to go in the header file.
Two basic options

1) common: put everything in header files. Look at boost, almost all of it is header-only, even the big libraries like boost.spirit or boost.graph. If it's against your aesthetics to see see code and interface in the same file, make another header file, foo-impl.h or details/foo.h, or similar, and include it from the file with the declarations.

2) rare: if you know every type that the users are allowed to instantiate your template with, like how std::complex knows that only float, double, and long double are valid parameters, then you can have a .cpp file with explicit instantiations of your template for all allowed types (and for multiple parameters, all combinations of allowed types). In C++11, this approach can be used even if full template definition is visible in the headers, with extern templates.
Thanks for the replies. I may be answering my own question here, but it sounds like template definitions inside declaration header files will work in 90% of cases, however I was able to find an edge case where template definitions inside separate files is imperative.

A.h
1
2
3
4
5
6
7
8
#pragma once   
#include "C.h" 
               
class A {      
        public:
        C c;   
        int a; 
};             


B.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma once              
                          
template<typename T>      
class B {                 
        public:           
        T t;              
        int getMember_a();
};                        
                          
                          
#include "A.h"            
template<typename T>      
int B<T>::getMember_a() { 
        return t.a;       
}                         


C.h
1
2
3
4
5
6
#pragma once         
#include "B.h"       
#include "D.h"       
                     
class C: public B<D>{
};                   


D.h
1
2
3
4
5
#pragma once  
              
class D {     
        int a;
}             


An error occurs when C.cpp is compiled:

1
2
3
4
5
6
7
$ gcc -c -o C.o C.cpp
In file included from B.h:11:0,
                 from C.h:2,
                 from C.cpp:1:
A.h:6:2: error: 'C' does not name a type
  C c;
  ^


The root of the problem is in B.h:11:0, where it must #include "A.h" (because it needs to access members of A). A.h must #include "C.h" because A is composed of C. Because A.h was included before C was defined, the compiler does not recognize it, and #pragma once prevents the preprocessor from including C.h again before the definition of A. Removing #pragma once would allow A to be completely defined, but a redefinition would happen once the include tree returns from C.h:2 and the rest of C.h is compiled.

It sounds like a classic circular dependency at first, but the following demonstrates that the problem is related to the defining of template member functions in B.h (more specifically, the inclusions that those definitions require). Here it is with a separate B.cpp file for definitions:

B.cpp (new):
1
2
3
4
5
#include "A.h"           
template<typename T>
int B<T>::getMember_a() {
        return t.a;
}      


B.h (modified):
1
2
3
4
5
6
7
8
#pragma once              
                          
template<typename T>      
class B {                 
        public:           
        T t;              
        int getMember_a();
};                        


Compilation succeeds:
1
2
$ gcc *.cpp -c
$


I conclude from this that the solution is composed of two rules:
1. Place definitions of member functions of template classes in a file separate from the declaration of the class.
2. Never #include definition files from header files, only from .cpp files where they are needed.

Once again, definitions in header files will probably work in 90% of cases. The classes in this example are tightly coupled, and the fact that the problem arose at all may be a symptom of bad design in the first place. Unusual as this problem is, it did come up in a real program I was writing.

Disclaimer: I've only been thinking about this problem for a short time, and I came up with the example on the spot, so if you see any mistakes, please point them out. I could be wrong.
I see no need for knowing A in your:
1
2
3
4
template<typename T>      
int B<T>::getMember_a() { 
        return t.a;       
}
In your demonstration, B.cpp compiles to an empty object file, it does not define anything at all. Templates aren't code.
keskiverto, Good point, I didn't notice that when I simplified the code for the example. What about this?

B.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once               
                           
class A;                   
template<typename T>       
class B {                  
        public:            
        T t;               
        A getMember_a(A a);
};                         
                           
                           
#include "A.h"             
template<typename T>       
A B<T>::getMember_a(A a) { 
        return t.a = a.a;    
}                          


If that doesn't do it, then definitions in header files it is.

Cubbi, B.cpp isn't meant to produce any object code itself, I just used the .cpp suffix to symbolize the fact that it contains definitions rather than declarations.
Topic archived. No new replies allowed.