When function templates are instantiated in a class template?

448 views Asked by At

At which moment the function templates within the following class template are instantiated?

// a.h

#pragma once

template <typename T>
class A {
public:
    template <typename T2> void func1(T2 t);
    void func2(T t);
    T    func3();
    void func4();

    // SECONDARY ISSUE
    // Is there any difference in writing this:
    A& operator=(A const&) = default;
    // or this:
    A<T>& operator=(A<T> const&) = default;
};

-----------------------------

// a.cpp

#include "a.h"

template <typename T>
template <typename T2>
void A<T>::func1(T2 t)
{
    // do sth
}

template <typename T>
void A<T>::func2(T t)
{
    // do sth
}
 
template <typename T>
T A<T>::func3()
{
    T t;
    // do sth
    return t; 
}

template <typename T>
void A<T>::func4()
{
    T t;
    // do sth with t
}

template class A<int>; // explicit instantiation

-----------------------------

// main.cpp

#include "a.h"

int main()
{
  A<int> a1;
  
  a1.func1<double>(1.);
  a1.func1(1.);
  a1.func2(2);
  a1.func3();
  a1.func4();
}

In a free function template the template is instantiated when it's called with a concrete type or with explicit instantiation.

What's the case with class templates? I guess func2() - func4() are instantiated with the explicit class template instantiation template class A<int>;. Or takes the instantiation place at the moment of the first function call, i.e. for example a1.func2(2.)?

In case of func1() the instantiation takes probably place with the call of a1.func1<double>(1.); as this is the first time when the second template parameter T2 is known?

Concerning the secondary issue: Does it matter if I write A or A<T>? I think it's the same but I am not sure about it.

1

There are 1 answers

1
463035818_is_not_an_ai On BEST ANSWER

Methods of class templates are only instantiated when called. For illustration consider:

#include <type_traits>

template <typename T>
struct foo {
    void only_for_int() {
        static_assert(std::is_same<T,int>::value);
    }
};


int main(){
    foo<int> f;
    f.only_for_int();   // OK (T == int)
    foo<double> d;      // OK
    //d.only_for_int(); // ERROR: static assert failed
}

Creating a foo<double> is fine. You just cannot call its method only_for_int. The fact that not every method must be valid is quite handy to allow types that cannot support all the templates requirements to use at least a subset of the templates methods.