1

When a function template is implicitly instantiated, is the declaration or the definition of the template required?

It seems that compilers only require a declaration:

template <typename T>
T f();

int g() {
  // Compiles OK, even though f's definition is not available here.
  return f<int>();
}

template <typename T>
T f() {
  return 123;
}

int main()
{
  std::cout << g();
}

I'm struggling to see where this behavior is specified in the Standard. Could anyone help finding that?

For example, doesn't the "temp.point" clause say that the point of f's instantiation should immediately follow g's definition, which should lead to compilation error as the f is not defined yet?

<...> the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.

Evg
  • 25,259
  • 5
  • 41
  • 83
Max
  • 59
  • 6
  • You declared `f()` that returns type `T`, in your `g` function you defined `T ` as `int` and the function to returns `int`, types are compatibles, that is all the compiler needs to know. –  May 16 '22 at 10:39
  • 3
    Dup of [Can the point-of-instantiation be delayed until the end of the translation unit?](https://stackoverflow.com/questions/23030403/can-the-point-of-instantiation-be-delayed-until-the-end-of-the-translation-unit) – Language Lawyer May 16 '22 at 11:07

1 Answers1

1

As long as there is a template declaration whose specialization is referred the program is valid. In your case, you have provided a template declaration for f that can be used by the compiler to know which specialization to call. The definition however can be provided later(as you did) and which is needed for the call to succeed(and not for the call to be bound to a function).

Moreover, the point of instantiation for the specialization f<int> will be just after g as highlighted in the below example using comments. In the below sample, point labeled #1 is the POI for the specialization f<int>.

Note also that from temp.point#7:

A specialization for a function template, a member function template, or of a member function or static data member of a class template may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above, for any such specialization that has a point of instantiation within the translation unit, the end of the translation unit is also considered a point of instantiation.

This means that there will be a second POI labeled as #2 in the below given example for the same specialization f<int>().

Thus both #1 and #2 labeled below, are considered POI for the specialization.

template <typename T>
T f();

int g() {
  
  return f<int>(); //#0 point of call but not point of instantiation
}
// #1: This is the first POI for f<int>()

template <typename T>
T f() {
  return 123;
}

int main()
{
  std::cout << g();
}

//#2 Second POI for f<int>() at the end of TU due to temp.point#7
Jason
  • 36,170
  • 5
  • 26
  • 60
  • @user17732522 The POI in the given example is at `#1` labeled in my given example. The point of call labeled `#0` cannot be a POI because at that point a definition of `f()` cannot be inserted. The point i am making(pun intended) is that for the call to be bound only a declaration can also work. But for the call to actually succeed the definition must be present somewhere later in the TU. – Jason May 16 '22 at 10:53
  • @user17732522 How would a function call look like? 1. Store on stack an address pointing to where to write the return value (in case of return value optimisation). 2. Store on stack the address of where to continue after a function call. 3. Store on stack the function parameters (as far as the calling conventions doesn't foresee them being passed by registers anyway) 4. Move instruction pointer to the address of the function. For the latter instruction only a placeholder is added to code, which is replaced only later by the linker. (Some minor details lacking). – Aconcagua May 16 '22 at 11:01
  • So all you now need to know is: 1. How do the parameters look like? Which is an appropriate location to provide for the return value. Actual location of the function (i.e. the implementation of) is irrelevant, thus the declaration suffices. – Aconcagua May 16 '22 at 11:02
  • @user17732522 By reading [temp.point#7](https://timsong-cpp.github.io/cppwp/n3337/temp.point#7), my understanding is that there are 2 POIs for `f()`. First is labeled `#1` in my example and second is at the end of this TU(labeled as `#2` above). – Jason May 16 '22 at 11:18
  • @user17732522 That comment wasn't precise (deleted already) – it's again the same, though: Specialisation needs to be declared before, but not defined – and compiler would need to scan the file for the specific specialisation. – Aconcagua May 16 '22 at 11:33
  • @Aconcagua Anyway, I don't think I actually disagree with anything you are saying and I feel my comments are kind of out-of-scope of the question, so I'll delete them. – user17732522 May 16 '22 at 11:34