-1

I'm wide awake at 1AM trying to figure out a compilation error I'm having. I can't really write the exact code but I'll do my best to make my question clear.

ClassWithTemplateFunction.hpp

#include "StructA.hpp"
#include "ClassB.hpp"
class ClassWithTemplateFunction
{
    template<typename A>
    void MyTemplateFunc();
}

ClassWithTemplateFunction.cpp

template<typename T>
void ClassWithTemplateFunction::MyTemplateFunc()
{
// code block
}

StructA.hpp

struct ClassWithTemplateFunction;
struct StructA
{
void StructAFunc(ClassWithTemplateFunction* templ);
}

StructA.cpp

#include "ClassWithTemplateFunction.hpp"
#include "StructA.hpp"
StructA::StructAFunc(ClassWithTemplateFunction* templ)
{
templ->MyTemplateFunc<SomeTemplate>();
}

The above codes work great. "SomeTemplate" is also another class. But then I added a new class which also uses the template function:

ClassB.hpp

class ClassWithTemplateFunction;
class ClassB
{
void ClassBFunc();
}

ClassB.cpp

#include "ClassB.hpp"
#include "ClassWithTemplateFunction.hpp"
void ClassB::ClassBFunc(ClassWithTemplateFunction* templ)
{
templ->MyTemplateFunc<SomeTemplate>();
}

And for some reason, this now introduced a linker error (undefined reference to MyTemplateFunc()). I can't figure out why it suddenly produced this issue. Obviously it can be fixed by moving the definition to the header file, but I want to understand, before adding ClassB, the code works just fine.

phoenixWright
  • 77
  • 1
  • 12
  • 1
    ClassWithTemplateFunction.cpp is wrong; at the very least it's missing `template `. You say you "can't really write the exact code" but you can and must present a [mcve] if you want a strong answer! Help us to help you. – Asteroids With Wings Apr 20 '20 at 17:34
  • Have a look at [Why can templates only be implemented in the header file](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file). The answer explains why it's working for one of the cases even though you are breaking this rule. – super Apr 20 '20 at 17:48
  • @AsteroidsWithWings The undefined reference error is the expected behaviour. Normally you would get it in both cases. But if the template has been instatiated with the exact same parameter in a different CU it will work. That's what explicit template instatiation does. I can understand that it can seem a bit confusing if your under the impressions that this code is valid in the normal case. – super Apr 20 '20 at 17:55
  • @super I'm not following you. The OP has two almost identical TUs, both of them distinct from the TU in which the template specialisation was defined. One of them allegedly generates a linker error, the other does not. That does not make sense. – Asteroids With Wings Apr 20 '20 at 18:00
  • 1
    @AsteroidsWithWings In that case I think you are. Looking at the code supplied by OP the usage in `StructA.cpp` should give an undefined reference error. But it's not. The only reason that could be is if OP has made an explicit template instatiation in `ClassWithTemplateFunction.cpp` and forgot to mention it. The much more likely explanation is that OP is using `MyTemplateFunc` in `ClassWithTemplateFunction.cpp` with the same type parameter as in `StructA.cpp` causing the template to be instatiated in that TU. Leadin to there not beaing any undefined reference error. – super Apr 20 '20 at 18:01
  • @super Yes, my strong belief is that the examples in the question are worthless. We need a [mcve] – Asteroids With Wings Apr 20 '20 at 18:01
  • @AsteroidsWithWings They are not worthless. They are actually accurate. It's just that OP is not aware that it should fail in the first case, so when it fails in the second he's getting even more confused. – super Apr 20 '20 at 18:02
  • @super How are they accurate if they (a) don't compile, and (b) don't reproduce the reported linker error (for reasons other than the compiler error)? – Asteroids With Wings Apr 20 '20 at 18:02
  • They will reproduce the linker error, but they will reproduce the linker errors for both `StructA.cpp` and `ClassB.cpp`. And yes, it's missing a `template ` in one place. Maybe some other mistakes aswell. I didn't try to compile it. Reading it is enough to grasp the situation IMO. – super Apr 20 '20 at 18:04
  • @super I reviewed the code after seeing your assumptions and the latter part was correct `"that OP is using MyTemplateFunc in ClassWithTemplateFunction.cpp with the same type parameter as in StructA.cpp causing the template to be instantiated in that TU"` Sorry, I actually missed mentioning that `ClassB` and `StructA` used to be inside `ClassWithTemplateFunction.cpp`, and what I was doing was separating into different files. Apparently `ClassB` was the last caller of `MyTemplateFunc()`. Thanks a lot for pointing this out. – phoenixWright Apr 21 '20 at 02:22

1 Answers1

2

If ClassWithTemplateFunction.cpp instantiates MyTemplateFunc with some template arguments somehow (e.g. by calling it), you'll be able to use MyTemplateFunc with the exact same arguments anywhere in the program.

That's why you don't get an undefined reference in the first case.

But it's not possible for an invocation of MyTemplateFunc with the exact same template arguments in a different file to cause an undefined reference. Please check if the template argument is really the same in both cases.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • If I'm reading the question correctly, that's the opposite of what they're finding. Not that makes sense.. – Asteroids With Wings Apr 20 '20 at 17:35
  • @AsteroidsWithWings Your definition of opposite seems strange... :-) – super Apr 20 '20 at 17:49
  • @super Does it? _"then I added a new class_ [in a new file] _which also uses the template function:_ [..] _And for some reason, this now introduced a linker error (undefined reference to MyTemplateFunc())"_ – Asteroids With Wings Apr 20 '20 at 17:51
  • as also mentioned by @super, this was the case for me. thank you for your effort, I had a better understanding with template functions now. – phoenixWright Apr 21 '20 at 02:27