I'm trying to learn templates and I've run into this confounding error. I'm declaring some functions in a header file and I want to make a separate implementation file where the functions will be defined.
Here's the code that calls the header (dum.cpp):
#include <iostream>
#include <vector>
#include <string>
#include "dumper2.h"
int main() {
std::vector<int> v;
for (int i=0; i<10; i++) {
v.push_back(i);
}
test();
std::string s = ", ";
dumpVector(v,s);
}
Now, here's a working header file (dumper2.h):
#include <iostream>
#include <string>
#include <vector>
void test();
template <class T> void dumpVector(const std::vector<T>& v,std::string sep);
template <class T> void dumpVector(const std::vector<T>& v, std::string sep) {
typename std::vector<T>::iterator vi;
vi = v.cbegin();
std::cout << *vi;
vi++;
for (;vi<v.cend();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;
}
With implementation (dumper2.cpp):
#include <iostream>
#include "dumper2.h"
void test() {
std::cout << "!olleh dlrow\n";
}
The weird thing is that if I move the code that defines dumpVector from the .h to the .cpp file, I get the following error:
g++ -c dumper2.cpp -Wall -Wno-deprecated
g++ dum.cpp -o dum dumper2.o -Wall -Wno-deprecated
/tmp/ccKD2e3G.o: In function `main':
dum.cpp:(.text+0xce): undefined reference to `void dumpVector<int>(std::vector<int, std::allocator<int> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
collect2: ld returned 1 exit status
make: *** [dum] Error 1
So why does it work one way and not the other? Clearly the compiler can find test(), so why can't it find dumpVector?
The problem you're having is that the compiler doesn't know which versions of your template to instantiate. When you move the implementation of your function to x.cpp it is in a different translation unit from main.cpp, and main.cpp can't link to a particular instantiation because it doesn't exist in that context. This is a well-known issue with C++ templates. There are a few solutions:
1) Just put the definitions directly in the .h file, as you were doing before. This has pros & cons, including solving the problem (pro), possibly making the code less readable & on some compilers harder to debug (con) and maybe increasing code bloat (con).
2) Put the implementation in x.cpp, and #include "x.cpp" from within x.h. If this seems funky and wrong, just keep in mind that #include does nothing more than read the specified file and compile it as if that file were part of x.cpp In other words, this does exactly what solution #1 does above, but it keeps them in seperate physical files. When doing this kind of thing, it is critical that you not try to compile the #included file on it's own. For this reason, I usually give these kinds of files an hpp extension to distinguish them from h files and from cpp files.
File: dumper2.h
#include <iostream>
#include <string>
#include <vector>
void test();
template <class T> void dumpVector( std::vector<T> v,std::string sep);
#include "dumper2.hpp"
File: dumper2.hpp
template <class T> void dumpVector(std::vector<T> v, std::string sep) {
typename std::vector<T>::iterator vi;
vi = v.begin();
std::cout << *vi;
vi++;
for (;vi<v.end();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;
}
3) Since the problem is that a particular instantiation of dumpVector is not known to the translation unit that is trying to use it, you can force a specific instantiation of it in the same translation unit as where the template is defined. Simply by adding this: template void dumpVector<int>(std::vector<int> v, std::string sep); ... to the file where the template is defined. Doing this, you no longer have to #include the hpp file from within the h file:
File: dumper2.h
#include <iostream>
#include <string>
#include <vector>
void test();
template <class T> void dumpVector( std::vector<T> v,std::string sep);
File: dumper2.cpp
template <class T> void dumpVector(std::vector<T> v, std::string sep) {
typename std::vector<T>::iterator vi;
vi = v.begin();
std::cout << *vi;
vi++;
for (;vi<v.end();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;
}
template void dumpVector<int>(std::vector<int> v, std::string sep);
By the way, and as a total aside, your template function is taking a vector by-value. You may not want to do this, and pass it by reference or pointer or, better yet, pass iterators instead to avoid making a temporary & copying the whole vector.
This was what the export keyword was supposed to accomplish (i.e., by exporting the template, you'd be able to put it in a source file instead of a header. Unfortunately, only one compiler (Comeau) ever really implemented export completely.
As to why the other compilers (including gcc) didn't implement it, the reason is pretty simple: because export is extremely difficult to implement correctly. Code inside the template can change meaning (almost) completely, based on the type over which the template is instantiated, so you can't generate a conventional object file of the result of compiling the template. Just for example, x+y might compile to native code like mov eax, x/add eax, y when instantiated over an int, but compile to a function call if instantiated over something like std::string that overloads operator+.
To support separate compilation of templates, you have to do what's called two-phase name lookup (i.e., lookup the name both in the context of the template and in the context where the template is being instantiated). You typically also have the compiler compile the template to some sort of database format that can hold instantiations of the template over an arbitrary collection of types. You then add in a stage between compiling and linking (though it can be built into the linker, if desired) that checks the database and if it doesn't contain code for the template instantiated over all the necessary types, re-invokes the compiler to instantiate it over the necessary types.
Due to the extreme effort, lack of implementation, etc., the committee has voted to remove export from the next version of the C++ standard. Two other, rather different, proposals (modules and concepts) have been made that would each provide at least part of what export was intended to do, but in ways that are (at least hoped to be) more useful and reasonable to implement.
Template parameters are resolved as compile time.
The compiler finds the .h, finds a matching definition for dumpVector, and stores it. The compiling is finished for this .h. Then, it continues parsing files and compiling files. When it reads the dumpVector implementation in the .cpp, it's compiling a totally different unit. Nothing is trying to instantiate the template in dumper2.cpp, so the template code is simply skipped. The compiler won't try every possible type for the template, hoping there will be something useful later for the linker.
Then, at link time, no implementation of dumpVector for the type int has been compiled, so the linker won't find any. Hence why you're seeing this error.
The export keyword is designed to solve this problem, unfortunately few compilers support it. So keep your implementation with the same file as your definition.
A template function is not real function. The compiler turns a template function into a real function when it encounters a use of that function. So the entire template declaration has to be in scope it finds the call to DumpVector, otherwise it can't generate the real function.
Amazingly, a lot of C++ intro books get this wrong.
This is exactly how templates work in C++, you must put the implementation in the header.
When you declare/define a template function, the compiler can't magically know which specific types you may wish to use the template with, so it can't generate code to put into a .o file like it could with a normal function. Instead, it relies on generating a specific instantiation for a type when it sees the use of that instantiation.
So when the implementation is in the .C file, the compiler basically says "hey, there are no users of this template, don't generate any code". When the template is in the header, the compiler is able to see the use in main and actually generate the appropriate template code.
Most compilers don't allow you to put template function definitions in a separate source file, even though this is technically allowed by the standard.
See also:
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.14
Related
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 7 years ago.
I have no idea why this is happenning, since I think I have everything properly declared and defined.
I have the following program, designed with templates. It's a simple implementation of a queue, with the member functions "add", "substract" and "print".
I have defined the node for the queue in the fine "nodo_colaypila.h":
#ifndef NODO_COLAYPILA_H
#define NODO_COLAYPILA_H
#include <iostream>
template <class T> class cola;
template <class T> class nodo_colaypila
{
T elem;
nodo_colaypila<T>* sig;
friend class cola<T>;
public:
nodo_colaypila(T, nodo_colaypila<T>*);
};
Then the implementation in "nodo_colaypila.cpp"
#include "nodo_colaypila.h"
#include <iostream>
template <class T> nodo_colaypila<T>::nodo_colaypila(T a, nodo_colaypila<T>* siguiente = NULL)
{
elem = a;
sig = siguiente;//ctor
}
Afterwards, the definition and declaration of the queue template class and its functions:
"cola.h":
#ifndef COLA_H
#define COLA_H
#include "nodo_colaypila.h"
template <class T> class cola
{
nodo_colaypila<T>* ult, pri;
public:
cola<T>();
void anade(T&);
T saca();
void print() const;
virtual ~cola();
};
#endif // COLA_H
"cola.cpp":
#include "cola.h"
#include "nodo_colaypila.h"
#include <iostream>
using namespace std;
template <class T> cola<T>::cola()
{
pri = NULL;
ult = NULL;//ctor
}
template <class T> void cola<T>::anade(T& valor)
{
nodo_colaypila <T> * nuevo;
if (ult)
{
nuevo = new nodo_colaypila<T> (valor);
ult->sig = nuevo;
ult = nuevo;
}
if (!pri)
{
pri = nuevo;
}
}
template <class T> T cola<T>::saca()
{
nodo_colaypila <T> * aux;
T valor;
aux = pri;
if (!aux)
{
return 0;
}
pri = aux->sig;
valor = aux->elem;
delete aux;
if(!pri)
{
ult = NULL;
}
return valor;
}
template <class T> cola<T>::~cola()
{
while(pri)
{
saca();
}//dtor
}
template <class T> void cola<T>::print() const
{
nodo_colaypila <T> * aux;
aux = pri;
while(aux)
{
cout << aux->elem << endl;
aux = aux->sig;
}
}
Then, I have a program to test these functions as follows:
"main.cpp"
#include <iostream>
#include "cola.h"
#include "nodo_colaypila.h"
using namespace std;
int main()
{
float a, b, c;
string d, e, f;
cola<float> flo;
cola<string> str;
a = 3.14;
b = 2.71;
c = 6.02;
flo.anade(a);
flo.anade(b);
flo.anade(c);
flo.print();
cout << endl;
d = "John";
e = "Mark";
f = "Matthew";
str.anade(d);
str.anade(e);
str.anade(f);
cout << endl;
c = flo.saca();
cout << "First In First Out Float: " << c << endl;
cout << endl;
f = str.saca();
cout << "First In First Out String: " << f << endl;
cout << endl;
flo.print();
cout << endl;
str.print();
cout << "Hello world!" << endl;
return 0;
}
But when I build, the compiler throws errors in every instance of the template class:
undefined reference to `cola(float)::cola()'... (it's actually cola'<'float'>'::cola(), but this doesn't let me use it like that.)
And so on. Altogether, 17 warnings, counting the ones for the member functions being called in the program.
Why is this? Those functions and constructors WERE defined. I thought that the compiler could replace the "T" in the template with "float", "string" or whatever; that was the advantage of using templates.
I read somewhere here that I should put the declaration of each function in the header file for some reason. Is that right? And if so, why?
This is a common question in C++ programming. There are two valid answers to this. There are advantages and disadvantages to both answers and your choice will depend on context. The common answer is to put all the implementation in the header file, but there's another approach will will be suitable in some cases. The choice is yours.
The code in a template is merely a 'pattern' known to the compiler. The compiler won't compile the constructors cola<float>::cola(...) and cola<string>::cola(...) until it is forced to do so. And we must ensure that this compilation happens for the constructors at least once in the entire compilation process, or we will get the 'undefined reference' error. (This applies to the other methods of cola<T> also.)
Understanding the problem
The problem is caused by the fact that main.cpp and cola.cpp will be compiled separately first. In main.cpp, the compiler will implicitly instantiate the template classes cola<float> and cola<string> because those particular instantiations are used in main.cpp. The bad news is that the implementations of those member functions are not in main.cpp, nor in any header file included in main.cpp, and therefore the compiler can't include complete versions of those functions in main.o. When compiling cola.cpp, the compiler won't compile those instantiations either, because there are no implicit or explicit instantiations of cola<float> or cola<string>. Remember, when compiling cola.cpp, the compiler has no clue which instantiations will be needed; and we can't expect it to compile for every type in order to ensure this problem never happens! (cola<int>, cola<char>, cola<ostream>, cola< cola<int> > ... and so on ...)
The two answers are:
Tell the compiler, at the end of cola.cpp, which particular template classes will be required, forcing it to compile cola<float> and cola<string>.
Put the implementation of the member functions in a header file that will be included every time any other 'translation unit' (such as main.cpp) uses the template class.
Answer 1: Explicitly instantiate the template, and its member definitions
At the end of cola.cpp, you should add lines explicitly instantiating all the relevant templates, such as
template class cola<float>;
template class cola<string>;
and you add the following two lines at the end of nodo_colaypila.cpp:
template class nodo_colaypila<float>;
template class nodo_colaypila<std :: string>;
This will ensure that, when the compiler is compiling cola.cpp that it will explicitly compile all the code for the cola<float> and cola<string> classes. Similarly, nodo_colaypila.cpp contains the implementations of the nodo_colaypila<...> classes.
In this approach, you should ensure that all the of the implementation is placed into one .cpp file (i.e. one translation unit) and that the explicit instantation is placed after the definition of all the functions (i.e. at the end of the file).
Answer 2: Copy the code into the relevant header file
The common answer is to move all the code from the implementation files cola.cpp and nodo_colaypila.cpp into cola.h and nodo_colaypila.h. In the long run, this is more flexible as it means you can use extra instantiations (e.g. cola<char>) without any more work. But it could mean the same functions are compiled many times, once in each translation unit. This is not a big problem, as the linker will correctly ignore the duplicate implementations. But it might slow down the compilation a little.
Summary
The default answer, used by the STL for example and in most of the code that any of us will write, is to put all the implementations in the header files. But in a more private project, you will have more knowledge and control of which particular template classes will be instantiated. In fact, this 'bug' might be seen as a feature, as it stops users of your code from accidentally using instantiations you have not tested for or planned for ("I know this works for cola<float> and cola<string>, if you want to use something else, tell me first and will can verify it works before enabling it.").
Finally, there are three other minor typos in the code in your question:
You are missing an #endif at the end of nodo_colaypila.h
in cola.h nodo_colaypila<T>* ult, pri; should be nodo_colaypila<T> *ult, *pri; - both are pointers.
nodo_colaypila.cpp: The default parameter should be in the header file nodo_colaypila.h, not in this implementation file.
You will have to define the functions inside your header file.
You cannot separate definition of template functions in to the source file and declarations in to header file.
When a template is used in a way that triggers its intstantation, a compiler needs to see that particular templates definition. This is the reason templates are often defined in the header file in which they are declared.
Reference:
C++03 standard, § 14.7.2.4:
The definition of a non-exported function template, a non-exported member function template, or a non-exported member function or static data member of a class template shall be present in every translation unit in which it is explicitly instantiated.
EDIT:
To clarify the discussion on the comments:
Technically, there are three ways to get around this linking problem:
To move the definition to the .h file
Add explicit instantiations in the .cpp file.
#include the .cpp file defining the template at the .cpp file using the template.
Each of them have their pros and cons,
Moving the defintions to header files may increase the code size(modern day compilers can avoid this) but will increase the compilation time for sure.
Using the explicit instantiation approach is moving back on to traditional macro like approach.Another disadvantage is that it is necessary to know which template types are needed by the program. For a simple program this is easy but for complicated program this becomes difficult to determine in advance.
While including cpp files is confusing at the same time shares the problems of both above approaches.
I find first method the easiest to follow and implement and hence advocte using it.
This link explains where you're going wrong:
[35.12] Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?
Place the definition of your constructors, destructors methods and whatnot in your header file, and that will correct the problem.
This offers another solution:
How can I avoid linker errors with my template functions?
However this requires you to anticipate how your template will be used and, as a general solution, is counter-intuitive. It does solve the corner case though where you develop a template to be used by some internal mechanism, and you want to police the manner in which it is used.
Note: Please take a moment and read the entire question if you are tempted to mark this as a duplicate. I have myself referenced the other related questions below but those questions are very much at the C++ language level. This question is at the C++ language level too but this question is also about API development for APIs involving templates that other questions do not seem to address.
I am exposing an API that to my users (client code). My API relies a lot on templates.
What does not work
Here is my API code:
// api.h
#include <vector>
template<typename T> void api_func(std::vector<T> v);
// api.cpp
#include <iostream>
#include <vector>
template<typename T> void api_func(std::vector<T> v)
{
// This prints just the size, but in the actual API, we would be
// doing more complex things.
std::cout << v.size() << '\n';
}
Here is a possible client code:
// client.cpp
#include "api.h"
int main()
{
std::vector<int> v {1, 2, 3, 4, 5};
// Although this client is calling the API with a std::vector<int>
// another client may call the API with another vector type such as
// std::vector<std::string>.
api_func(v);
}
Of course, this does not compile.
$ clang++ -std=c++11 api.cpp client.cpp
Undefined symbols for architecture x86_64:
"void api_func<int>(std::__1::vector<int, std::__1::allocator<int> >)", referenced from:
_main in client-2a152c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
What works
This issue has been discussed extensively on Stack Overflow already in the following posts:
Why can templates only be implemented in the header file?
Why do C++ template definitions need to be in the header?
Define template in header file and definition in a cpp file within derived class
According to those discussions, one way to fix the issue is by moving the template definition to header file too.
// api.h - fixed
#include <iostream>
#include <vector>
template<typename T> void api_func(std::vector<T> v)
{
// This prints just the size, but in the actual API, we would be
// doing more complex things.
std::cout << v.size() << '\n';
}
# api.cpp is unnecessary now
rm api.cpp
# client.cpp remains the same
This does compile now.
$ clang++ -std=c++11 client.cpp && ./a.out
5
Questions
The resolution shows that if I don't want to commit to specific types for the template parameters in my API (to ensure that the client has the flexibility to choose types appropriate to their needs), then any functions relying on template parameters need to be defined in the header file itself.
But when I do this for all functions in my API, it appears that all my business logic has moved to the header file. So my entire API is now a giant collection of .H files with absolutely no .CPP files.
My questions:
Am I doing something wrong that has caused my entire API implementation to be composed only of .H files and no .CPP files?
How are APIs like these generally designed? Are there any other techniques to bring back implementation code into .CPP files such that only minimum possible stuff goes into .H files?
You have dropped from your question the part that determines how to solve it. The body of your templates matter to determine how exactly to hide them (or if it is possible). But I will answer with what you gave me.
Your problem is basically the problem of type erasure.
Start with this:
template<typename T> void api_func(std::vector<T> v);
this erases no information about the type v.
But what are we using:
template<typename T> void api_func(std::vector<T> v) {
// This prints just the size, but in the actual API, we would be
// doing more complex things.
std::cout << v.size() << '\n';
}
here, we are extracting the .size() from the vector, then manipulating that.
The fact we are then streaming it to cout is not a fact about the type being passed in; the fact we expect it to have a .size() is.
struct has_dot_size_ref {
template<class T,
std::enable_if_t< !std::is_same<T, has_dot_size_ref>{}, bool> = true
>
has_dot_size_ref( T const& t ):
ptr( std::addressof(t) ),
call_dot_size([](void const* ptr)->std::size_t{
return static_cast<T const*>(ptr)->size();
})
{}
std::size_t size() const {
return call_dot_size(ptr);
}
private:
void const* ptr = 0;
std::size_t(*call_dot_size)(void const*) = 0;
};
this is a type eraser. It takes its argument, and erases everything about it except the fact that the object has a .size() member that returns std::size_t.
Now in the header:
void api_func(has_dot_size_ref v);
and in the cpp file:
void api_func(has_dot_size_ref v) {
// This prints just the size, but in the actual API, we would be
// doing more complex things.
std::cout << v.size() << '\n';
}
and now the code works.
If you are doing something more complicated, work out what exactly you need from the type in question, erase down to exactly those properties.
Some of your code remains in header files, others does not.
Not every problem can be type erased this way; sometimes the type erasure is the entire method. And these techniques, because they are manual, take a bit of work. In addition, the type erasure barrier can be expensive (to that end, sometimes you type erase range operations instead of element operations; or even synthesize the type erased range operation from a written element operation).
Simple question - why do I have to #include "listType.cpp" or get linker errors here? Why can't I just include the header?
stockListType.h:
#ifndef stockListType_H
#define stockListType_H
#include "listType.h"
#include "stockType.h"
#include "listType.cpp"
using namespace std;
class stockListType : public listType<stockType>
{
private:
unique_ptr<int[]> sortIndicesByGainLoss;
public:
void sortByStockSymbol();
void sortByGainLoss();
stockListType(int maxSize);
};
#endif
This happens because in a traditional C++ compiler approach template code "doesn't exist" as a "material execution entity" until it's instantiated for some "real" types (stockType in your case). There're however techniques called explicit instantiation which allows to to specify during processing of "listType.cpp" that later you will need an instance of the code for e.g. stockType, otherType and int. Read from this: http://msdn.microsoft.com/en-us/library/by56e477.aspx or this: http://www.cplusplus.com/forum/articles/14272/ or this: How do I explicitly instantiate a template function?
Also another reason for using a source, not pre-compiled code of template classes and functions is that it's possible to override later an implementation of a given template class, method or function for a particular template argument (recall the famous std::cout << "Hello, World " << 1 << MyClassObject << std::endl, that's the classical case when operator<<(ostream&, T&) is defined for each particular type separately.
Besides, if you take a look into standard C++ STL library (e.g. <vector> or <string>) you will see that the whole code of the classes is right in header files, or files included from header files (.tcc) even a rather complex one (see Boost.Spirit, well, if you're brave enough :) ). That's because it's not possible to create an executable code for vector until vector elements (stockType etc) are defined.
Using this tutorial Makefile I want to build a simple program with a separate compiling, The main problem is that the IDE Eclpse Indigo C\C++ (prespective) or MinGW I cannot compile the files. The error which I get is :
undefined reference to double getAverage<int, 85u>(int (&) [85u])'
undefined reference to int getMax<int, 85u>(int (&) [85u])'
undefined reference to int getMin<int, 85u>(int (&) [85u])'
undefined reference to void print<int, 85u>(int (&) [85u])'
undefined reference to void sort<int, 85u>(int (&) [85u])'
undefined reference to void print<int, 85u>(int (&) [85u])'
The main.cpp file is this :
#include "Tools.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
int numbers[] = {1,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8,-2,7,14,5,6,16,8};
cout <<"Average = "<< getAverage(numbers) << endl;
cout <<"Max element = "<< getMax(numbers) << endl;
cout <<"Minimal element = "<< getMin(numbers) << endl;
print(numbers);
sort(numbers);
print(numbers);
return 0;
}
and I have a Tools.h file :
#ifndef TOOLS_H_
#define TOOLS_H_
#include <iostream>
int getBigger(int numberOne,int numberTwo);
template <typename T,size_t N> double getAverage(T (&numbers)[N]);
template <typename T,size_t N> T getMax(T (&numbers)[N]);
template <typename T,size_t N> T getMin(T (&numbers)[N]);
/**
* Implementing a simple sort method of big arrays
*/
template <typename T,size_t N> void sort(T (&numbers)[N]);
/**
* Implementing a method for printing arrays
*/
template <typename T,size_t N> void print(T (&numbers)[N]);
#endif
When you compile Tools.cpp your compiler has no idea about the template parameters that you have used in main.cpp. Therefore it compiles nothing related to this templates.
You need to include theses template definitions from the compilation unit that uses them. The file Tools.cpp is often renamed to something like Tools.inl to indicate that it's neither a header file nor a separate compilation unit.
The compilation unit "main.cpp" could look like this:
#include "tools.h"
#include "tools.inl"
main()
{
int number[] = {1,2,3};
getaverage(numbers);
}
Since the compiler identifies the required specialization it can generate the code from the implementation file.
For most cases, harper's answer is appropriate. But for completeness' sake, explicit template instantiation should also be mentioned.
When you include the implementation in every compilation unit, your template classes and functions will be instantiated and compiled in all of them. Sometimes, this is not desirable. It is mostly due to compile-time memory restrictions and compilation time, if your template classes and functions are very complicated. This becomes a very real issue when you, or the libraries you use rely heavily on template metaprogramming. Another situation could be that your template function implementations might be used in many compilation units, and when you change the implementation, you will be forced to re-compile all those compilation units.
So, the solution in these situations is to include a header file like your tools.h, and have a tools.cpp, implementing the templates. The catch is that, you should explicitly instantiate your templates for all the template arguments that will be used throughout your program. This is accomplished via adding the following to tools.cpp:
template double getAverage<int,85>(int (&numbers)[85]);
Note: You obviously have to do something about that "85", such as defining it in a header file and using it across tools.cpp and main.cpp
I've found this article which is useful : templates and header files
I declared the function in the Tools.h file and include there the file Tool.hpp and after this I defined them in the Tools.hpp file.
I haven't tried to compile .cpp and .c files together but maybe my example will help.
I had similar problem compiling two separate assembly files .s on mingw with standard gcc
compiler and i achieved it as follows:
gcc -m32 -o test test.s hello.s
-m32 means i'm compiling 32bit code
-o is the output file ( which in my example is the "test" file )
test.s and hello.s are my source files. test.s is the main file and hello.s has the helper function. (Oh, to mention is the fact that both files are in the same directory)
I am getting errors trying to compile a C++ template class which is split between a .hpp and .cpp file:
$ g++ -c -o main.o main.cpp
$ g++ -c -o stack.o stack.cpp
$ g++ -o main main.o stack.o
main.o: In function `main':
main.cpp:(.text+0xe): undefined reference to 'stack<int>::stack()'
main.cpp:(.text+0x1c): undefined reference to 'stack<int>::~stack()'
collect2: ld returned 1 exit status
make: *** [program] Error 1
Here is my code:
stack.hpp:
#ifndef _STACK_HPP
#define _STACK_HPP
template <typename Type>
class stack {
public:
stack();
~stack();
};
#endif
stack.cpp:
#include <iostream>
#include "stack.hpp"
template <typename Type> stack<Type>::stack() {
std::cerr << "Hello, stack " << this << "!" << std::endl;
}
template <typename Type> stack<Type>::~stack() {
std::cerr << "Goodbye, stack " << this << "." << std::endl;
}
main.cpp:
#include "stack.hpp"
int main() {
stack<int> s;
return 0;
}
ld is of course correct: the symbols aren't in stack.o.
The answer to this question does not help, as I'm already doing as it says.
This one might help, but I don't want to move every single method into the .hpp file—I shouldn't have to, should I?
Is the only reasonable solution to move everything in the .cpp file to the .hpp file, and simply include everything, rather than link in as a standalone object file? That seems awfully ugly! In that case, I might as well revert to my previous state and rename stack.cpp to stack.hpp and be done with it.
It is not possible to write the implementation of a template class in a separate cpp file and compile. All the ways to do so, if anyone claims, are workarounds to mimic the usage of separate cpp file but practically if you intend to write a template class library and distribute it with header and lib files to hide the implementation, it is simply not possible.
To know why, let us look at the compilation process. The header files are never compiled. They are only preprocessed. The preprocessed code is then clubbed with the cpp file which is actually compiled. Now if the compiler has to generate the appropriate memory layout for the object it needs to know the data type of the template class.
Actually it must be understood that template class is not a class at all but a template for a class the declaration and definition of which is generated by the compiler at compile time after getting the information of the data type from the argument. As long as the memory layout cannot be created, the instructions for the method definition cannot be generated. Remember the first argument of the class method is the 'this' operator. All class methods are converted into individual methods with name mangling and the first parameter as the object which it operates on. The 'this' argument is which actually tells about size of the object which incase of template class is unavailable for the compiler unless the user instantiates the object with a valid type argument. In this case if you put the method definitions in a separate cpp file and try to compile it the object file itself will not be generated with the class information. The compilation will not fail, it would generate the object file but it won't generate any code for the template class in the object file. This is the reason why the linker is unable to find the symbols in the object files and the build fails.
Now what is the alternative to hide important implementation details? As we all know the main objective behind separating interface from implementation is hiding implementation details in binary form. This is where you must separate the data structures and algorithms. Your template classes must represent only data structures not the algorithms. This enables you to hide more valuable implementation details in separate non-templatized class libraries, the classes inside which would work on the template classes or just use them to hold data. The template class would actually contain less code to assign, get and set data. Rest of the work would be done by the algorithm classes.
I hope this discussion would be helpful.
It is possible, as long as you know what instantiations you are going to need.
Add the following code at the end of stack.cpp and it'll work :
template class stack<int>;
All non-template methods of stack will be instantiated, and linking step will work fine.
You can do it in this way
// xyz.h
#ifndef _XYZ_
#define _XYZ_
template <typename XYZTYPE>
class XYZ {
//Class members declaration
};
#include "xyz.cpp"
#endif
//xyz.cpp
#ifdef _XYZ_
//Class definition goes here
#endif
This has been discussed in Daniweb
Also in FAQ but using C++ export keyword.
No, it's not possible. Not without the export keyword, which for all intents and purposes doesn't really exist.
The best you can do is put your function implementations in a ".tcc" or ".tpp" file, and #include the .tcc file at the end of your .hpp file. However this is merely cosmetic; it's still the same as implementing everything in header files. This is simply the price you pay for using templates.
Only if you #include "stack.cpp at the end of stack.hpp. I'd only recommend this approach if the implementation is relatively large, and if you rename the .cpp file to another extension, as to differentiate it from regular code.
I believe there are two main reasons for trying to seperate templated code into a header and a cpp:
One is for mere elegance. We all like to write code that is wasy to read, manage and is reusable later.
Other is reduction of compilation times.
I am currently (as always) coding simulation software in conjuction with OpenCL and we like to keep code so it can be run using float (cl_float) or double (cl_double) types as needed depending on HW capability. Right now this is done using a #define REAL at the beginning of the code, but this is not very elegant. Changing desired precision requires recompiling the application. Since there are no real run-time types, we have to live with this for the time being. Luckily OpenCL kernels are compiled runtime, and a simple sizeof(REAL) allows us to alter the kernel code runtime accordingly.
The much bigger problem is that even though the application is modular, when developing auxiliary classes (such as those that pre-calculate simulation constants) also have to be templated. These classes all appear at least once on the top of the class dependency tree, as the final template class Simulation will have an instance of one of these factory classes, meaning that practically every time I make a minor change to the factory class, the entire software has to be rebuilt. This is very annoying, but I cannot seem to find a better solution.
Sometimes it is possible to have most of implementation hidden in cpp file, if you can extract common functionality foo all template parameters into non-template class (possibly type-unsafe). Then header will contain redirection calls to that class. Similar approach is used, when fighting with "template bloat" problem.
If you know what types your stack will be used with, you can instantiate them expicitly in the cpp file, and keep all relevant code there.
It is also possible to export these across DLLs (!) but it's pretty tricky to get the syntax right (MS-specific combinations of __declspec(dllexport) and the export keyword).
We've used that in a math/geom lib that templated double/float, but had quite a lot of code. (I googled around for it at the time, don't have that code today though.)
The problem is that a template doesn't generate an actual class, it's just a template telling the compiler how to generate a class. You need to generate a concrete class.
The easy and natural way is to put the methods in the header file. But there is another way.
In your .cpp file, if you have a reference to every template instantiation and method you require, the compiler will generate them there for use throughout your project.
new stack.cpp:
#include <iostream>
#include "stack.hpp"
template <typename Type> stack<Type>::stack() {
std::cerr << "Hello, stack " << this << "!" << std::endl;
}
template <typename Type> stack<Type>::~stack() {
std::cerr << "Goodbye, stack " << this << "." << std::endl;
}
static void DummyFunc() {
static stack<int> stack_int; // generates the constructor and destructor code
// ... any other method invocations need to go here to produce the method code
}
The place where you might want to do this is when you create a library and header combination, and hide the implementation to the user. Therefore, the suggested approach is to use explicit instantiation, because you know what your software is expected to deliver, and you can hide the implementations.
Some useful information is here:
https://learn.microsoft.com/en-us/cpp/cpp/explicit-instantiation?view=vs-2019
For your same example:
Stack.hpp
template <class T>
class Stack {
public:
Stack();
~Stack();
void Push(T val);
T Pop();
private:
T val;
};
template class Stack<int>;
stack.cpp
#include <iostream>
#include "Stack.hpp"
using namespace std;
template<class T>
void Stack<T>::Push(T val) {
cout << "Pushing Value " << endl;
this->val = val;
}
template<class T>
T Stack<T>::Pop() {
cout << "Popping Value " << endl;
return this->val;
}
template <class T> Stack<T>::Stack() {
cout << "Construct Stack " << this << endl;
}
template <class T> Stack<T>::~Stack() {
cout << "Destruct Stack " << this << endl;
}
main.cpp
#include <iostream>
using namespace std;
#include "Stack.hpp"
int main() {
Stack<int> s;
s.Push(10);
cout << s.Pop() << endl;
return 0;
}
Output:
> Construct Stack 000000AAC012F8B4
> Pushing Value
> Popping Value
> 10
> Destruct Stack 000000AAC012F8B4
I however don't entirely like this approach, because this allows the application to shoot itself in the foot, by passing incorrect datatypes to the templated class. For instance, in the main function, you can pass other types that can be implicitly converted to int like s.Push(1.2); and that is just bad in my opinion.
You need to have everything in the hpp file. The problem is that the classes aren't actually created until the compiler sees that they're needed by some OTHER cpp file - so it has to have all the code available to compile the templated class at that time.
One thing that I tend to do is to try to split my templates into a generic non-templated part (which can be split between cpp/hpp) and the type-specific template part which inherits the non-templated class.
Because templates are compiled when required, this forces a restriction for multi-file projects: the implementation (definition) of a template class or function must be in the same file as its declaration. That means that we cannot separate the interface in a separate header file, and that we must include both interface and implementation in any file that uses the templates.
Another possibility is to do something like:
#ifndef _STACK_HPP
#define _STACK_HPP
template <typename Type>
class stack {
public:
stack();
~stack();
};
#include "stack.cpp" // Note the include. The inclusion
// of stack.h in stack.cpp must be
// removed to avoid a circular include.
#endif
I dislike this suggestion as a matter of style, but it may suit you.
The 'export' keyword is the way to separate out template implementation from template declaration. This was introduced in C++ standard without an existing implementation. In due course only a couple of compilers actually implemented it. Read in depth information at Inform IT article on export
1) Remember the main reason to separate .h and .cpp files is to hide the class implementation as a separately-compiled Obj code that can be linked to the user’s code that included a .h of the class.
2) Non-template classes have all variables concretely and specifically defined in .h and .cpp files. So the compiler will have the need information about all data types used in the class before compiling/translating generating the object/machine code
Template classes have no information about the specific data type before the user of the class instantiate an object passing the required data type:
TClass<int> myObj;
3) Only after this instantiation, the complier generate the specific version of the template class to match the passed data type(s).
4) Therefore, .cpp Can NOT be compiled separately without knowing the users specific data type. So it has to stay as source code within “.h” until the user specify the required data type then, it can be generated to a specific data type then compiled
I am working with Visual studio 2010, if you would like to split your files to .h and .cpp, include your cpp header at the end of the .h file