I have searched high and low for answers on this but I'm still baffled. As far as I understand from the examples I've found online my code should be valid but it won't compile due to undefined references. I figured out how to get it to compile but I think that's not how one is supposed to do it. So the following is a question I'd very much appreciate answers to.
I'd like to implement a class in C++ with a template member similarly to how std::vector for example can contain data of any type. The following is a minimal example that reproduces the issue.
main.cpp:
#include <iostream>
#include <cstdlib>
#include "Foo.h"
int main(int argc, char** argv) {
Foo<int> foo_int;
Foo<float> foo_flt;
return 0;
}
Foo.h:
#ifndef FOO_H
#define FOO_H
template<class T> class Foo {
public:
Foo();
Foo(const Foo& orig) = delete;
virtual ~Foo();
private:
T* m_f;
};
#endif /* FOO_H */
Foo.cpp
#include <iostream>
#include <typeinfo>
#include "Foo.h"
template<class T> Foo<T>::Foo() {
std::cout << "Constructing a Foo<" << typeid(T).name() << ">!" << std::endl;
m_f = new T;
}
template<class T> Foo<T>::~Foo() {
std::cout << "Destructing a Foo<" << typeid(T).name() << ">!" << std::endl;
}
Now if I try to build the code in NetBeans IDE I get the following output.
cd '/home/pete/Dropbox/NetBeans/Foodinger'
/usr/bin/make -f Makefile CONF=Debug
"/usr/bin/make" -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
make[1]: Entering directory '/home/pete/Dropbox/NetBeans/Foodinger'
"/usr/bin/make" -f nbproject/Makefile-Debug.mk dist/Debug/GNU-Linux/foodinger
make[2]: Entering directory '/home/pete/Dropbox/NetBeans/Foodinger'
mkdir -p build/Debug/GNU-Linux
rm -f "build/Debug/GNU-Linux/Foo.o.d"
g++ -c -g -std=c++14 -MMD -MP -MF "build/Debug/GNU-Linux/Foo.o.d" -o build/Debug/GNU-Linux/Foo.o Foo.cpp
mkdir -p build/Debug/GNU-Linux
rm -f "build/Debug/GNU-Linux/main.o.d"
g++ -c -g -std=c++14 -MMD -MP -MF "build/Debug/GNU-Linux/main.o.d" -o build/Debug/GNU-Linux/main.o main.cpp
mkdir -p dist/Debug/GNU-Linux
g++ -o dist/Debug/GNU-Linux/foodinger build/Debug/GNU-Linux/Foo.o build/Debug/GNU-Linux/main.o
build/Debug/GNU-Linux/main.o: In function `main':
/home/pete/Dropbox/NetBeans/Foodinger/main.cpp:8: undefined reference to `Foo<int>::Foo()'
/home/pete/Dropbox/NetBeans/Foodinger/main.cpp:9: undefined reference to `Foo<float>::Foo()'
/home/pete/Dropbox/NetBeans/Foodinger/main.cpp:9: undefined reference to `Foo<float>::~Foo()'
/home/pete/Dropbox/NetBeans/Foodinger/main.cpp:8: undefined reference to `Foo<int>::~Foo()'
/home/pete/Dropbox/NetBeans/Foodinger/main.cpp:8: undefined reference to `Foo<int>::~Foo()'
collect2: error: ld returned 1 exit status
nbproject/Makefile-Debug.mk:63: recipe for target 'dist/Debug/GNU-Linux/foodinger' failed
make[2]: *** [dist/Debug/GNU-Linux/foodinger] Error 1
make[2]: Leaving directory '/home/pete/Dropbox/NetBeans/Foodinger'
nbproject/Makefile-Debug.mk:60: recipe for target '.build-conf' failed
make[1]: *** [.build-conf] Error 2
make[1]: Leaving directory '/home/pete/Dropbox/NetBeans/Foodinger'
nbproject/Makefile-impl.mk:39: recipe for target '.build-impl' failed
make: *** [.build-impl] Error 2
BUILD FAILED (exit value 2, total time: 760ms)
My understanding is that one should only #include
header files and the .cpp files should be given as arguments to the compiler. That's what the build seems to be doing according to its output. If I however add #include "Foo.cpp"
to main.cpp the program seems to compile and run just fine. But isn't this how one is not supposed to do it? Or have I found some special case here where I have to #include
the .cpp file? Is NetBeans doing something wrong? Is there something wrong with my implementation using templates? At least the code compiles fine if I get rid of them.
Thanks.