This problem is in defining and declaring a function template in a namespace that is defined in an external file from where the function is instantiated. Here's the smallest reproducible example I could come up with. 4 files follow:
The function template declaration in a named namespace:
// bar.h
#include <algorithm>
namespace barspace {
template <typename Iter>
void DoSomething (Iter first, Iter last);
}
The function template definition in a separate file:
// bar.cpp
#include "bar.h"
namespace barspace {
template <typename Iter>
void DoSomething (Iter first, Iter last) {
typedef typename std::iterator_traits<Iter>::value_type val_t;
std::sort (first, last);
}
} // namespace barspace
The header for the main program
// foo.h
#include "bar.h"
#include <vector>
Lastly, the main program where the function template is called:
//foo.cpp
#include "foo.h"
int main () {
std::vector<double> v_d;
for (int i = 0; i < 10; i++) {
v_d.push_back (i);
}
barspace::DoSomething (v_d.begin(), v_d.end());
return 0;
}
I compile as follows:
g++ -c -o bar.o bar.cpp
g++ -c -o foo.o foo.cpp
These run fine. Now for linking:
g++ bar.o foo.o -o foobar
And the resulting compiler error about the undefined reference:
foo.o: In function `main':
foo.cpp:(.text+0x6e): undefined reference to `void barspace::DoSomething<__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > > >(__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >, __gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >)'
collect2: ld returned 1 exit status
There is an obvious problem with the code not getting made available from within the namespace
, or from the bar
compilation unit.
Furthermore, when I try to place the definition of DoSomething
in the bar.h
header, as I would to circumvent the issues when defining class template methods in separate .cpp files, I get the same error.
Can you shed some light unto my compiler linking error?
You are trying to hide the implementation of your templated function into the cpp file, which, unfortunately, is not possible for most compilers. Templated functions/classes are instantiated when used, so at the point where you are calling DoSomething
, the compiler needs the definition of the function to be able to compile it.
There are a couple of solutions.
Move the function body into the header file. You had trouble doing that before, but i'd say it's related to something else. This is the preferred approach.
Include the cpp file from foo.cpp
. (wild, but not that uncommon).
Instantiate the template for double
:
// bar.cpp
#include "bar.h"
namespace barspace {
template<>
void DoSomething<double> (double first, double last) {
typedef typename std::iterator_traits<double>::value_type val_t;
std::sort (first, last);
}
} // namespace barspace
Putting templates definitions in a separate source file is not well supported (I believe the only compiler that support that is Comeau).
You need to move the definition into your header files:
// bar.h
namespace barspace {
template <typename Iter>
void DoSomething (Iter first, Iter last) {
typedef typename std::iterator_traits<Iter>::value_type val_t;
std::sort (first, last);
}
} // namespace barspace
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With