I am working on a static library and the library has multiple class templates and function templates. I understand in order to use the templates inside static library everything (declaration/definition) needs to be in the header file. However, in this particular case since I know the specialization types I thought I can use forward declare the specialization instead.
This trick works nicely with the class templates (and its functions) and I can use all the library function from my application code. However, as soon as I introduce free function template inside the library and I try to use the free templated function from my application code it gives me linker error:
error LNK2019: unresolved external symbol "class TemplatedStaticLib __cdecl HelpingRegistration(int)" (??$HelpingRegistration@H@@YA?AV?$TemplatedStaticLib@H@@H@Z) referenced in function _main 1>C:\src\cpp\vs2008\StaticLibExample\MathFuncsLib\Debug\TemplatedStaticLibApp.exe : fatal error LNK1120: 1 unresolved externals" I am using VS2008, here is the code
//Static library header file (.h)
#ifndef _TEMPLATED_STATIC_LIB_
#define _TEMPLATED_STATIC_LIB_
#include <iostream>
template<typename T>
class TemplatedStaticLib
{
public:
TemplatedStaticLib(){};
~TemplatedStaticLib(){};
void print(T t);
};
template<typename T>
TemplatedStaticLib<T> HelpingRegistration(T);
#endif
//static library class file (.cpp)
#include "TemplatedStaticLib.h"
//Specialization
template class TemplatedStaticLib<double>;
template class TemplatedStaticLib<int>;
template class TemplatedStaticLib<std::string>;
template<typename T>
void TemplatedStaticLib<T>::print(T t)
{
std::cout << "Templated Print " << typeid(t).name() << std::endl;
}
void HelpingRegistration(void)
{
}
//Specialization of free function
template<> TemplatedStaticLib<int> HelpingRegistration<int>(int);
template<> TemplatedStaticLib<double> HelpingRegistration<double>(double);
template<> TemplatedStaticLib<std::string> HelpingRegistration<std::string>(std::string);
template<typename T>
TemplatedStaticLib<T> HelpingRegistration(T t)
{
std::cout << "Function Templated Print " << typeid(t).name() << std::endl;
return t;
}
//Application code
#include "TemplatedStaticLib.h"
int main(int argc, char* argv[])
{
int anInt = 99;
TemplatedStaticLib<int> test;
test.print(anInt);//works
double aDouble = 3.9;
TemplatedStaticLib<double> double_test;
double_test.print(aDouble); //works
std::string aString = "James";
TemplatedStaticLib<std::string> string_test;
string_test.print(aString);//works
//The following lines gives linker error
HelpingRegistration(anInt);
HelpingRegistration(aDouble);
HelpingRegistration(aString);
return 0;
}
I am not sure why it is different and how I can fix this. Any help is appreciated.
Class templates and static variables: Each instantiation of class template has its own copy of member static variables. For example, in the following program there are two instances Test and Test. So two copies of static variable count exist.
Class templates and static variables: The rule for class templates is same as function templates Each instantiation of class template has its own copy of member static variables. For example, in the following program there are two instances Test and Test.
In addition to forward declaration of explicit instantiations (with extern ), G++ has extended the template instantiation syntax to support instantiation of the compiler support data for a template class (i.e. the vtable) without instantiating any of its members (with inline ), and instantiation...
This syntax is defined in the C++ 2011 standard, but has been supported by G++ and other compilers since well before 2011. Explicit instantiations can be used for the largest or most frequently duplicated instances, without having to know exactly which other instances are used in the rest of the program.
Mind the fact that those are not forward declarations, but rather explicit instantiations of your class templates. That is what allows you to put the definition in a .cpp
files and get no unresolved reference error by the linker, as long as in other translation units you only use those template instantiations.
On the other hand, these:
template<> TemplatedStaticLib<int> HelpingRegistration<int>(int);
template<> TemplatedStaticLib<double> HelpingRegistration<double>(double);
template<> TemplatedStaticLib<std::string> HelpingRegistration<std::string>(std::string);
are declarations of explicit specializations of function templates. What you most likely intended to do is, instead, to provide explicit instantiations. The syntax for doing that is the following:
template TemplatedStaticLib<int> HelpingRegistration<>(int);
template TemplatedStaticLib<double> HelpingRegistration<>(double);
template TemplatedStaticLib<std::string> HelpingRegistration<>(std::string);
Once you will fix that, you will see that the compiler will actually instantiate your HelpingRegistration<>()
function template, and it will also emit an error while doing so, because you are trying to convert an int
(resp. a double
or string
) to an object of type TemplatedStaticLib<int>
(resp. TemplatedStaticLib<double>
or TemplatedStaticLib<string>
), for which no conversion is provided (or at least not shown in the code you posted):
template<typename T>
TemplatedStaticLib<T> HelpingRegistration(T t)
{
std::cout << "Function Templated Print " << typeid(t).name() << std::endl;
return t; // CANNOT BE CONVERTED!
}
Fixing this error (e.g. by doing return TemplateStaticLib<T>();
) will make the program compile and link.
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