0

Without optimization flags, the following code compiles fine, but with -O1 both g++ and clang++ throw undefined reference to 'void Foo::Fooify<int>(int)'

Adding an explicit instantiation in foo.cpp solves the issue, but that seems redundant to me after an implicit instantiation. Is it really necessary to do that or are the compiler optimizations at fault here?

//foo.h

struct Foo {
  template <class T>
  void Fooify(T);
  void UseFooifyForInt();
};
//foo.cpp

#include foo.h

template <class T>
void Foo::Fooify(T) {}

void Foo::UseFooifyForInt() {
  Fooify(5);
}
//main.cpp

#include foo.h

int main() {
  Foo f{};
  f.Fooify(42);
}

This question is currently marked as a duplicate of Why can templates only be implemented in the header file?, but one of the solutions given there is to explicitly instantiate the templates in the .cpp file (in my case that would be foo.cpp. I am wondering why an implicit instantiation does not work for this use case.

tcnops
  • 1
  • 2
  • The compiler will inline `Fooify` in `foo.cpp` so won't export the symbol – Alan Birtles Jun 03 '22 at 13:33
  • If you remove `Fooify(5);` from `foo.cpp` then at the point when you wrote `f.Fooify(42);` the linker doesn't have the definition of `Foo::Fooify(T)` as the header only has a declaration for that member function and not the definition and hence you get the mentioned linker error. On the other hand, if you have `Fooify(5);` in `foo.cpp` then that member functions will be instantiated and hence its definition is available and so `f.Fooify(42);` will work here without any linker error in this case. – Jason Jun 03 '22 at 13:35
  • @AnoopRana only if compiler optimisations are disabled – Alan Birtles Jun 03 '22 at 13:47
  • @AlanBirtles Thanks for the comment. So is it correct to say that it's unsafe to rely on implicit instantiations because the compiler might inline those, making them unavailable? While an explicit instantiation would never be inlined? – tcnops Jun 03 '22 at 14:14
  • Yes, explicit instantiations signal your intent to use the template elsewhere, implicit ones don't so the compiler happily throws them away – Alan Birtles Jun 03 '22 at 16:19
  • @AlanBirtles Thanks! It surprises me that a compiler optimization can change observable behavior like this though. Doesn't that violate the as-if rule? Or would you rather say my program is malformed without the explicit instantiation? – tcnops Jun 03 '22 at 16:36
  • Yep, it's malformed and just happens to work without optimisations enabled – Alan Birtles Jun 03 '22 at 16:39

0 Answers0