问题
Consider following code:
myclass.h :
template <class T>
struct S {
void f();
};
struct MyClass : public S<int>
{
void g();
};
myclass.cpp :
#include "myclass.h"
#include <iostream>
template <class T>
void S<T>::f()
{
std::cout << "f()\n";
/* some code here that could not be in header */
}
void MyClass::g()
{
std::cout << "g()\n";
}
main.cpp :
#include "myclass.h"
int main()
{
MyClass m;
m.g();
m.f(); // problem here
}
I've got linker error:
undefined reference to `S::f()'
Can I solve this issue without transferring implementation of S::f() to header file? Why S::f() not instantiated when I declare a MyClass derived from full specialized template base class?
回答1:
Why S::f() not instantiated when I declare a MyClass derived from full specialized template base class?
Because your myclass.cpp makes no use of that template, and like all unused templates in translation units, they amount to nothing in the produced code. The derivation is all well and good, and if MyClass::g()
used S<T>::f()
you would pull in that code and life would be good. But you don't, so you have to pull it in another way...
You should be able to do this with explicit instantiation. Note the following addition to your .cpp file:
#include "myclass.h"
#include <iostream>
template <class T>
void S<T>::f()
{
std::cout << "f()\n";
}
void MyClass::g()
{
std::cout << "g()\n";
}
template struct S<int>; // ADDED
Be warned, however. This will only work if the only usage is S<int>
. Additional expansions would need additional entries of explicit instantiations.
You could also do it with direct specialization, such as changing your .cpp to just do this:
#include "MyClass.h"
#include <iostream>
template <>
void S<int>::f()
{
std::cout << "f()\n";
}
void MyClass::g()
{
std::cout << "g()\n";
}
but that would be rather limiting in my mind, as each additional type you add would need its own specialization.
Anyway, best of luck.
回答2:
Adding an explicit instantiation
template
struct S<int>;
to "myclass.cpp" makes the code compile.
Loosely speaking, the derivation from S<int>
only "instantiates" the class definition, not the members.
There is no way for the compiler to instantiate f
at that point since the definition of f
isn't known.
You'll need to provide explicit instantiations for all the types you're using, which somewhat limits the utility of the template.
A popular way of keeping template definitions out of headers is to have them in their own file which is #include
d at the end of the header.
回答3:
You can't solve this problem without transferring implementation of s::f() function to header file. this is because compiler must know implementation of template before using it.
来源:https://stackoverflow.com/questions/28212558/undefined-reference-to-member-function-of-template-base-class