1

I am trying to understand extern templates, but i can't get it to work. My goal is to compile some instanciations if Foo<> in a seperate compilation unit in order to save compilation time. In my code base, the template argument is a enum class, so in theory I am able to compile all instanciations in a compilation unit and link them with the rest of the project.

Here is a little example I come up with:

//Foo.hpp
#pragma once

template <class T>
struct Foo {
    Foo();
    ~Foo();
};

extern template struct Foo<int>;

//Foo.cpp
#include "Foo.hpp"

template struct Foo<int>;

//main.cpp
#include <iostream>

#include "Foo.hpp"

int main(int argc, char **argv) {
   Foo<int> foo;

    return 0;
}

To for compilation i used a makefile, that boils down to this:

g++ -c ../Foo.cpp ../main.cpp
g++ Foo.o main.o 

The output I get with gcc 7.1.1 and basically the same with clang 4.0.1 is:

main.o: In function `main':
main.cpp:(.text+0x27): undefined reference to `Foo<int>::Foo()'
main.cpp:(.text+0x38): undefined reference to `Foo<int>::~Foo()'

My main question is, why is Foo<int>::Foo() and Foo<int>::~Foo()not compiled into Foo.o?

vsoftco
  • 55,410
  • 12
  • 139
  • 252
OutOfBound
  • 1,914
  • 14
  • 31
  • 1
    Because you provided absolutely nothing to the compiler to let it know what the constructor and the destructor do. Do they add two numbers? Subtract two numbers? Count the number of words in "War And Peace"? Count the number of angels on the tip of a pin? You have to write the constructor, somewhere, you know, in order for the compiler to instantiate it. – Sam Varshavchik Jul 26 '17 at 22:05

1 Answers1

3

Because the constructor and destructor are not defined anywhere, you only declare them. You correctly explicitly instantiate the template in the Foo.cpp file, but the functions are still not defined.

If you are only going to use Foo<int>, then you can define the constructor and destructor in Foo.cpp,

template<typename T>
Foo<T>::Foo(){...} // or = default

and

template<typename T>
Foo<T>::~Foo(){...}

and due to the fact that you explicitly instantiate the template in the Foo.cpp the linker will find the definition. Otherwise, you need to provide the definition in the header file.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • 1
    Got it. I overlook it because i was focused on the extern templates. Thank you. – OutOfBound Jul 26 '17 at 22:09
  • @OutOfBound See also https://stackoverflow.com/q/8130602/3093378 for more details about real-world usage of `extern template`s. – vsoftco Jul 26 '17 at 22:10
  • I can't tell whether the intention of the code in this example is to demonstrate template function definitions for `Foo` or for `Foo`. For the former, add `` before the two `::` s; for the latter you need `template <> Foo::Foo() {...}` and similarly for the destructor. – Pete Becker Jul 26 '17 at 22:11
  • @PeteBecker Forgot the ``, edited. I think both approaches you mentioned can be used here, provided OP is using only the `Foo` instantiation. – vsoftco Jul 26 '17 at 22:13