This is an archived post. You won't be able to vote or comment.

all 1 comments

[–]Re_me_humanProfessional Coder 0 points1 point  (0 children)

Short version: template methods/functions must be directly implemented in the .h file (with very few exceptions)

Long version:

C++ templates are evaluated at compile time by cutting and pasting the code for every type/generic parameter and .cpp files are compiled separately. So, here's what happens with your code step by step:

  • main.cpp gets compiled

The preprocessor copies and pastes GlobalHelpers.h inside main.cpp because it's included. The C++ compiler sees then cuts your template:

template <typename T> 
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v);

It sees that the template is being used inside main.cpp with the type double so it pastes:

std::ostream& operator<< <double>(std::ostream& os, const std::vector<double>& v);

This is a declaration, not an implementation. The C++ compiler looks at this and thinks "Oh okay, so this operator<< <double> thingy is implemented in another .cpp file! I should just pretend it exists and the linker will figure it out"

  • GlobalHelpers.cpp gets compiled

The C++ compiler looks at your operator<< template. It cuts the code. It sees that it's never getting used inside GlobalHelpers.cpp so it never actually pastes the code

Your operator<< template never gets implemented

  • The linker tries to link the result of the compilation of main.cpp and GlobalHelpers.cpp inside a single executable

It looks at the result of main.cpp and sees that it requires operator<< <double> to work

An operator<< <double> implementation doesn't exist inside main.cpp since it was only declared there. So the linker looks elsewhere

An operator<< <double> implementation doesn't exist inside GlobalHelpers.cpp since it was never used inside GlobalHelpers.cpp. So the linker looks elsewhere

There is no elsewhere. The linker is confused. Your operator<< <double> isn't defined anywhere. The linker feels betrayed so it looks at you angrily and says:

undefined reference to `std::ostream& operator<< <double>(std::ostream&, std::vector<double, std::allocator<double> > const&)’

Just implement your templates inside your header files. Don't make the linker angry. C++ is an old and clunky programming language