Reputation: 92
I have an overloaded function, their definitions are the same and only one parameter change. So, I tried to create a template function but when I call it I got a symbol lookup error.
Header file
void func(Myobject obj);
void func(MySecondObject obj);
Source file
template<typename T>
void func(T obj) { obj.foo(); }
Test file
#include "MyHeaderFile.h"
func(MySecondObject()); // symbol lookup error at runtime
Thanks.
Upvotes: 1
Views: 570
Reputation: 23681
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.
Upvotes: 7
Reputation: 1323
I would suggest defining the template specializations in the source file. It hides the template specializations in the current translation unit.
MyHeaderFile.h
template <typename T>
void func(T obj);
MyHeader.cpp
#include <iostream>
#include "MyHeaderFile.h"
template <typename T>
void func(T obj)
{
std::cout << "function name: " << __func__;
}
template void func<MySecondObject>(MySecondObject obj);
template void func<Myobject>(Myobject obj);
I hope this answer solves your problem.
Upvotes: 1
Reputation: 8218
It seems that you want to have a template function with two explicit instantiations for MyObject
and MySecondObject
. Template function declaration should be in your header like that:
template<typename T>
void func(T obj);
Then in the corresponding source file you should provide generic implementation + explicit instantiations:
#include "header.hpp"
template<typename T>
void func(T obj)
{
obj.foo();
}
template void func<MyObject>(MyObject obj);
template void func<MySecondObject>(MySecondObject obj);
Then you can use that two versions in your code:
func(MyObject());
func(MySecondObject());
but call to func
with another template parameter, e.g. func('c')
will result in undefined reference.
cpp reference section "Explicit instantiation".
Upvotes: 1