I am creating my own implementation of a List ADT and I am really confused as to a linker error that I am getting. When I compile with
g++ -std=c++11 problem1.cpp main.cpp -o Problem1
I get this error:
1 2 3 4 5 6
/tmp/cceo20TV.o: In function `main':
main.cpp:(.text+0xdd): undefined reference
to `List<int>::List(std::vector<int, std::allocator<int> >&)'
main.cpp:(.text+0xf3): undefined reference
to `List<int>::List(std::vector<int, std::allocator<int> >&)'
collect2: error: ld returned 1 exit status
I know this probably has something to do with how I called instances of my class due to my confusion regarding how to implement templates. What am I doing wrong here?
Your template class, List, is needed to be explicit instantiation in problem1.cpp. If not, List<int> is not instantiated for problem1.o, which means the type is missing in linker stage.
> But I want it to be instantiated in main.cpp, right?
Member functions (constructor, initialize() etc) are all template function, and compiled in problem1.cpp. Therefore, List<int>::XXX is missing in linker stage.
>Otherwise, doesn't it destroy the point of having a template?
Do you mean such a treatment degrades the usefulness of template as generic programming?
Some library based on template techniques (c.f. boost) implements all (not only declaration, but definition) in the header, which enables generic programming for arbitrary template arguments.
So did I make the template a class rather than a typename? Is that part of the issue? Why am I supposed to put template class List<int> at the bottom of my .cpp file? I don't want it to be int. I want it to be able to take whatever data type it is initialized as in main.
The above code defines template class "List" is instantiated as List<int>.
If you need other types, you can add instantiated classes like the below
1 2 3 4
templateclass List<int>;
templateclass List<double>;
templateclass List<std::string>;
// just add the definitions
If you do not like it, (1) all codes in problem1.cpp and problem1.h should be moved into main.cpp, or (2) write the implementations of problem.cpp in the problem1.h.
Oh I get it now. So since I am compiling the .cpp file and and .h file separately, the compiler won't know what data type I input when I created an instance of the class?
Precisely speaking, the minimum unit of the compile is each .cpp file. (statements in .h file is just inserted into the .cpp by #include). Thus, main.cpp and problem1.cpp are compiled independently.
You intended to instantiate List<int> in main.cpp, but it is not instantiated in problem1.cpp.
main.cpp does not know definition of List<int>, but it is forwardly declared in problem1.h, so that such a forward declaration tells compiler that "Though now the definition is unknown, it is added in linker stage".
But, it is not defined in other place (problem1.cpp) , which leads to the error "undefined reference of List<int>::XXX" because there is no definition of List<int>::XXX.
It is something confusing, but, it is internally related to compiler procedure in C++.
Ah. That makes sense. The linker knows that the member constructors, variables, and functions have been declared but because the .cpp file is compiled separately, it has no idea what the definitions are. Thank you for the help!