If you say
void func(Myobject obj);
void func(MySecondObject obj);
then you promise to the compiler that it will eventually find
void func(Myobject obj)
{ /* implementation */ }
void func(MySecondObject obj)
{ /* implementation */ }
Since you didn't provide these implementations (there are no definitions for these symbols you declared), you get an error.
What you can do however is this:
Header file
void func(Myobject obj);
void func(MySecondObject obj);
Source file
template<typename T>
void func_impl(T obj) { obj.foo(); }
void func(Myobject obj) { func_impl(obj); }
void func(MySecondObject obj) { func_impl(obj); }
This allows you to declare and define "real" (non-templated) functions for your users, but you can still implement all of them by delegating the work to the same template function. It is best practice to put the func_impl
into an unnamed namespace (namespace /* no name here */ { /* code goes here */ }
) which will make it internal to that translation unit (and also makes it clear that it's not intended to be seen/used by other code, without having to cross-reference the header).
(The following is already discussed at Why can templates only be implemented in the header file?).
An alternative approach is to declare the function template in the header, then define it in the source file and provide explicit instantiations for the types you want:
Header file
template<class T>
void func(T obj);
// Explicit instantiation declarations
extern template void func<Myobject>(Myobject obj);
extern template void func<MySecondObject>(MySecondObject obj);
Source file
template<typename T>
void func(T obj) { obj.foo(); }
// Explicit instantiation definitions
template void func<Myobject>(Myobject obj);
template void func<MySecondObject>(MySecondObject obj);
This approach is significantly more verbose, potentially confusing for users that are not template-affine, and trying to use it with the wrong type leads to linker errors instead of a nicer compiler error, so the first solution above can easily be the most appropriate.
Or you could define the entire template in the header file. There can be good reasons to avoid that though.