It’s because templates are instantiated at compile-time, not link-time, and different translation units (roughly equivalent to your
.cpp files) only “know about” each other at link-time. Headers tend to be widely “known about” at compile-time because you
#include them in any translation unit that needs them.
Read https://isocpp.org/wiki/faq/templates for more.