'When does instantiation happens for explicit instantiation of a function template

Hi i am learning about explicit instantiation. And so reading different examples but in one example have some doubts. The example is given below and i have 2 doubts in this particular example.

File Application.cc contains:

extern template int compare(const int&, const int&);
int i = compare(a1[0], a2[0]);// instantiation will appear elsewhere

File templateBuild.cc contains:

template int compare(const int&, const int&);

Also note that the function template compare is:

template<typename T, typename F = less<T>>
int compare(const T &v1, const T &v2, F f = F())
{
  if (f(v1,v2)) return -1;
  if (f(v2,v1)) return 1;
  return 0;
}

My questions are as follows:

  1. As you can see in the Application.cc file in the 2nd line it is written(as a comment) that instantiation will appear elsewhere. But here we are using the template function as int i = compare(a1[0], a2[0]); and we know that whenever we use a template function the compiler will instantiate it. So why is that comment written there? Also in the explanation it is written that

When the compiler sees an instantiation definition (as opposed to a declaration), it generates code. Thus, the file templateBuild.o will contain the definitions for compare instantiated with int.

So my question is if the compiler generates code whenever it sees an instantiation definition and so templateBuild.o will contain the definition of compare instantiated with int then how can we use compare() in the Application.cc file using compare(a1[0], a2[0]);? I mean the compare() template is not yet instantiated so how can we use it before it is instantiated?

  1. My 2nd question is that where should i write(put) the content of the compare() template. For example in a header file or in the Application.cc file? By the content of the compare() template i mean the 3rd block of code that i have given in the example.


Solution 1:[1]

I suppose you are dealing with a case, where the function template is defined in a header file, which is then included into both source files. Something as (for simplicity, I removed the functional parameter):

// compare.h

template<typename T>
int compare(const T &v1, const T &v2)
{
  if (v1 < v2) return -1;
  if (v2 < v1) return 1;
  return 0;
}
// Application.cc

#include <compare.h>

extern template int compare(const int&, const int&);
int i = compare(1, 2); 
// templateBuild.cc

#include <compare.h>

template int compare(const int&, const int&);

Now, it is useful to visualize how translation units look like for both these source files.

  1. Translation unit for Application.cc:
template<typename T>
int compare(const T &v1, const T &v2)
{
  if (v1 < v2) return -1;
  if (v2 < v1) return 1;
  return 0;
}

extern template int compare(const int&, const int&);
int i = compare(1, 2);

When a compiler translates (compiles) this translation unit, it sees only the explicit instantiation declaration. If it wasn't there, the compare function call would cause implicit definition instantiation. But since it is there, this implicit instantiation is avoided, as written here:

An explicit instantiation declaration (an extern template) prevents implicit instantiations: the code that would otherwise cause an implicit instantiation has to use the explicit instantiation definition provided somewhere else in the program.

Consequently, a compiler only generates machine code for calling compare<int> as it was a normal (non-template) function with its declaration but not definition in the translation unit.

Live demo: https://godbolt.org/z/1c8jvvcv1

Note that there is no machine code generated for compare<int>.

  1. Translation unit for templateBuild.cc:
template<typename T>
int compare(const T &v1, const T &v2)
{
  if (v1 < v2) return -1;
  if (v2 < v1) return 1;
  return 0;
}

template int compare(const int&, const int&);

Here, we have an explicit instantiation definition, which causes the function template to be instantiated as compare<int>.

Live demo: https://godbolt.org/z/o9vxPvP75

Now, the machine code for compare<int> has been generated.

Solution 2:[2]

Question 1)

extern template int compare(const int&, const int&);

With this line, you can suppress the implicit instantiation of a template specialization or its members. That's what the comment in the second line means. In this current example, the explicit instantiation definition is in the templateBuild.cc file. You can find a detailed explanation here.

Question 2)

You have to put the template class definition and declaration in the same (header) file. For more details please have a look at this page.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Attis