Explicit instantiation example for a templated function

Hi everyone,

when dealing with templated classes/functions, it's common practice to put both declarations and definitions inside the header, rather than writing them separately and using explicit instatiation.

Let's say we have an [i]header file foo.hpp[\i] where we write the declaration of the templated function foo

1
2
3
4
5
6
7
8
9
#ifndef foo_hpp
#define foo_hpp


template <typename T>
void foo();


#endif /* foo_hpp */ 




Then, we write a [i]foo.cpp[\i] file where we define the function and **use explicit instantiation**

1
2
3
4
5
6
7
8
9
10
#include "foo.hpp"
#include <iostream>


template <typename T>
void foo(){
    std::cout << "Call to foo \n";
}

template void foo<int>(); //explicit istantiation 



Now in the main.cpp file, the one I want to execute, I have
1
2
3
4
5
6
7
#include "foo.hpp"

int main(){
    
    foo<int>();
    return 0;
}


In order to compile (with -std=c++14 flag), I have to do

 
g++ -o main.x -std=c++14 main.cpp foo.cpp


The question is: **is this the correct way to run compile the main file using explicit instantiation** ?

If I simply do:
 
g++ -o main.x -std=c++14 main.cpp 


we have undefined symbols because the compiler doesn't have access to the implementation of the methods.

Last edited on
Use an explicit instantiation declaration in the header file
https://en.cppreference.com/w/cpp/language/function_template#Explicit_instantiation

extern template void foo<int>(); //explicit istantiation declaration

Last edited on
I wrote that line in my header foo.hpp, but it's not compiling because a linkage error occurs.

Shouldn't I do the explicit instantiation in the .cpp file, as wrote in the accpeted answer at https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file ?
Here is a complete example:

main.cpp
1
2
3
4
5
6
7
template <int N> int foo();
extern template int foo<42>();

int main()
{
  foo<42>();
}


foo.cpp
1
2
template <int N> int foo() { return N; }
template int foo<42>();

http://coliru.stacked-crooked.com/a/6cf7f3df0f971722
Thanks @mbozzi for your snippet. Shouldn't you include your foo.cpp in your main? In that case, I understand your snippet works.

But I was concerned with the splitting in header/source and main, as I wrote in my question. Could you please tell me if the way I compile is the correct one? Or what people do in general when they want to do things that way?

To me, it's a bit weird because I need to compile also the source foo.cpp, but maybe this is precisely because of explicit instantiation.
Last edited on
Sorry @VoB, I should have read your post more carefully.

To compile main.cpp alone you need to pass the -c flag to the compiler, as in
g++ -o main.cpp.o -std=c++14 -c main.cpp
This compiles but does not link main.cpp. The output is an object file, which must later be linked with the other object files into an executable.

main.cpp.o references symbols that are defined elsewhere -- for example, the explicit instantiation
template int foo<42>();
is defined elsewhere, in foo.cpp.o

Therefore foo.cpp must be compiled as well
g++ -o foo.cpp.o -std=c++14 -c foo.cpp
And the two object files linked together
g++ -o main.x main.cpp.o foo.cpp.o

Alternatively, if you want the compiler to manage these details, you can write
g++ -o main.x -std=c++14 main.cpp foo.cpp
to compile and link everything at once. As you've already discovered.
Last edited on
Thanks, now I have finally got it: first I create the object codes, and then I link them together.

I also tried to do the same you did here, but with my own example and it works !


However, there's still something unclear to me: shouldn't you include foo.cpp in your main.cpp ? Or did you just overcame this by using extern?
Last edited on
However, there's still something unclear to me: shouldn't you include foo.cpp in your main.cpp ? Or did you just overcame this by using extern

In this case, extern is the workaround. It tells the compiler "this function template is explicitly instantiated later, maybe in a different translation unit; do not waste time implicitly instantiating it".

Of course, since the definition of the function template is not available within main.cpp it could not be implicitly instantiated within main.cpp anyway. If we omitted the explicit instantiation declaration we'd get a linker error.

In a conventional build setup, .cpp files are never included. Each .cpp file is considered part of an independent translation unit and compiled separately.
Last edited on
Okay, now it's clear to me the purpose of extern.

However, why do you have to write template <int N> int foo(); at the beginning of the file? Why isn't just extern template int foo<42>(); sufficient?

Why isn't just extern template int foo<42>() sufficient

Firstly, there's not enough information in the explicit instantiation declaration alone to determine which template instantiation is being declared.

For example, the primary template could have default template arguments:
1
2
// template <int N, int = 1> int foo(); 
extern template int foo<42>(); 

If the first line was un-commented, the second line would declare an explicit instantiation of
template int foo<42, 1>();

Secondly, and more importantly, unlike generics in other languages, C++ templates are purely a meta-programming facility. They do not exist in the compiled code. They only tell the compiler how to write code for you.

The function template
template <int N> int bar() { std::cout << N << '\n'; }
Exists only at compile-time as an instruction to the compiler. The function template tells the compiler how to write a set of independent functions (incl. template int bar<1>() and template int bar<251>()) for the programmer on demand.

If I try to call bar<2>() in my source code, the compiler must locate the corresponding function template, which is
template <int N> int bar() { std::cout << N << '\n'; }
and substitute N with 10 to produce this actual function
template int bar<10>() { std::cout << 10 << '\n'; }
which can then be called. (This process is called implicit instantiation.)

The compiler must be able to "see" the template's definition to generate code
. This means the template's definition must be visible from the same translation unit which instantiates the template. See also this stack overflow answer:
https://stackoverflow.com/q/495021/2085046
Last edited on
I see, thanks so much. Btw, I have just a quick question about another possible way to split the declaration and definition. In particular I'm referring to the accepted answer's solution, the one using a .tpp file.

Namely:

First we have the .tpp file:

1
2
3
4
5
6
7
8
9
10
//foo.tpp file

#include "foo.hpp"
#include <iostream>


template <typename T>
void foo(){
    std::cout << "Call to foo \n";
}



Then include the .tpp in the .hpp

1
2
3
4
5
6
7
8
9
10
11
12
//foo.hpp file 

#ifndef foo_hpp
#define foo_hpp


template <typename T>
void foo();

#include "foo.tpp" //here we include the .tpp in the .hpp

#endif /* foo_hpp */ 



And the the main is the same as before:

1
2
3
4
5
6
7
#include "foo.hpp"

int main(){
    
    foo<int>();
    return 0;
}



The question is: in this way, since the .tpp files has #include "foo.hpp" and it's included also in the .hpp, isn't like if the .hpp file is self-contained?
Last edited on
In this way, the since the .tpp files has #include "foo.hpp" and it's included also in the .hpp, isn't like if the .hpp file is self-contained?

Remember that #include "xyz" means "Paste the contents of xyz here".

Given the header file,
1
2
3
4
5
#ifndef foo_hpp
#define foo_hpp
 //... 
#include "foo.tpp"
#endif 


So when foo.tpp is included the results are
1
2
3
4
5
6
7
8
9
#ifndef foo_hpp
#define foo_hpp
  //... 
#  ifndef foo_hpp
#  define foo_hpp
     //... 
#  include "foo.tpp"
#  endif
#endif 

But the preprocessor conditional on line 4 doesn't expand because foo_hpp is defined already on line 2.

These are "header" or "include" guards:
https://www.learncpp.com/cpp-tutorial/header-guards/
Last edited on
Okay, everything is clear now.

I also agree about the thing you wrote and then deleted, i.e. to put both declaration and definition in the header.

Thanks for your time and valuable suggestions :-)
Last edited on
Actually, I've just seen something I shouldn't have done.

Look at mine .tpp file: I can avoid to write #include foo.hpp because actually I do not need to compile it, but just to "past" its content in the header foo.hpp.

Indeed, it still compiles, but in this case I have not self-inclusion.

Is everything correct? :-)
I'm really sorry for bothering you, but could you please confirm my last message?

I'd like to be sure about that point.
I'm really sorry for bothering you, but could you please confirm my last message?

It's no problem -- I've just been busy.
Is everything correct?

Yes, there's no need to include foo.hpp from foo.tpp.
Thanks for the check !
Topic archived. No new replies allowed.