How to use Templates efficiently ?

Hello everyone,
I recently started fiddling with generic programming and want to improve on it.
As I am programming microcontrollers, the size of the created code matters a lot more than usual.
The common way of writing the prototypes in the .h and the implementation into the corresponding .cpp does not work due to the way the linker works.
What I want to achieve is:
- Using template classes split up into two files.
- Minimizing the resulting code size.
Which are good ways to achieve this?

What I found so far:
https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl
http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file
http://stackoverflow.com/questions/115703/storing-c-template-function-definitions-in-a-cpp-file
Several solutions are provided in these sources, but I dont know which would be most efficient. I strongly dislike the explicit instantiation in form of
 
template class GenericClass<int,10>;
as I think it defies the generic Concept.
Some of the solutions are used in the following example.

GenericClass.h :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template<typename T1, T1 BUFFER_SIZE >
class GenericClass
{
	public:
	GenericClass(){}
	void pushValue(T1 value) // Implementation 1
  	{
 		_buffer[0] = value;
 	}
 	T1 getValue();
 	T1 foo();
 	~GenericClass(){};
 	private:
 	T1 _a, _b;
 	T1 _buffer[BUFFER_SIZE];
};

// Implementation 2, works and currently my way to go
template<typename T1, T1 BUFFER_SIZE >
T1 GenericClass<T1, BUFFER_SIZE>::getValue()
{
	return _buffer[0];
}

GenericClass.cpp :
1
2
3
4
5
6
7
8
9
#include "GenericClass.h"

// Implementation 3 , leads to Linker Error 
// "undefined reference to 'GenericClass<int, 10>::foo()'
template<typename T1, T1 BUFFER_SIZE >
T1 GenericClass<T1, BUFFER_SIZE>::foo()
{
	return _buffer[0];
}


Including the .cpp at the end of .h leads to "expected initializer before '<' token":
1
2
3
4
5
6
7
8
9
10
11
// GenericClass.h
//...  like above
#include "GenericClass.cpp"

// GenericClass.cpp
// Implementation 4
template<typename T1, T1 BUFFER_SIZE > 
T1 GenericClass<T1, BUFFER_SIZE>::foo()
{
	return _buffer[0];
}


http://isocpp.org/wiki/faq/templates#separate-template-fn-defn-from-decl
The above mentions using extern to solve linker errors, but has not been updated so far. I dont know how I would use this.

I work with AtmelStudio and the AVR/GNU C++ compiler (C++ 11 Standard, without most libraries). Still I am interested in general answers.

Thanks for your time.
Last edited on
The way you are doing it now creates circular dependency: cpp file includes h and h includes cpp.
One of the common approaches is to move implementation to .tpp file an include it at the end oh .h:
1
2
3
4
5
6
7
template<typename T>
class foo
{
    /*...*/
};

#include "foo.tpp" 


About the code: each different istantiation is generating own class/function. Like as if you copy/pasted everything to a new file and replaced templated parameters with new one.
Usually compilers are good with throwing out unneeded code (making stuff like compile-time calculations using templates essentually free), but it can vary depending on optimisation parameters. Best way is to test it before actually using.
Last edited on
Thanks for the input. My example of implementation 4 was probably not unambigous.
I refined it here. The .cpp does not refer to the .h so there should not be a circular dependency.
Header :
1
2
3
4
5
6
7
8
9
10
11
12
template<typename T1, T1 BUFFER_SIZE >
class GenericClass
{
	public:
	GenericClass(){};
	T1 foo();
	~GenericClass(){};
	private:
	T1 _buffer[BUFFER_SIZE];
};

#include "GenericClass.cpp" 

GenericClass.cpp :
1
2
3
4
5
template<typename T1, T1 BUFFER_SIZE >
T1 GenericClass<T1, BUFFER_SIZE>::foo() // Error : expected initializer before '<' token
{
	return _buffer[0];
}

I think this is now close to your example, however I still get a compile error at the implementation. This solution would at least achieve separate files.
When I rename the .cpp to .tpp and update the include, the compilation succedes, but I actually dont know why.

Cant find a source, but I read that considering (non-generic) classes optimization wise the implementations should not be in the header or at least not to be combined with the prototypes. The reason was somewhere along the lines of potentially generating separate code for every include elsewise. Maybe this is compiler specific?
Last edited on
When I rename the .cpp to .tpp and update the include, the compilation succedes, but I actually dont know why.
IDE will probably try to compile any file with extension cpp, which is not what you want: it is not a standalone compilation unit, but just an addon to the template header and should not be compiled separately. You can change extention or exclude that file from compile list manually.

Cant find a source, but I read that considering (non-generic) classes optimization wise the implementations should not be in the header or at least not to be combined with the prototypes. The reason was somewhere along the lines of potentially generating separate code for every include elsewise. Maybe this is compiler specific?
It is the same like with inline functions: linker can optimize away redundand code, but does not have to. GCC guys are proud of their optimizer, so double code will be eliminated with very high chance.

implementations should not be in the header
Only way to truly separate implementation from declaration is to use explicit instantiation (variant with including implementation file in header does not do that, as include is just copy-paste and is used here just for convenience)
Thank you again for those insights. They already improved my understanding a lot.
I will use the include in the header file for now.
Going to visit the official FAQ from time to time to see if they updated it with the use of
extern template, to see what is possible with it.
Topic archived. No new replies allowed.