Когда шаблоны функций создаются в шаблоне класса?

В какой момент создаются экземпляры шаблонов функций в следующем шаблоне класса?

// 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();
}

В шаблоне свободной функции экземпляр шаблона создается, когда он вызывается с конкретным типом или с явным созданием экземпляра.

Что происходит с шаблонами классов? Я предполагаю, что func2() - func4() создаются с явным созданием экземпляра шаблона класса template class A<int>;. Или занимает место инстанцирования в момент первого вызова функции, т.е. например a1.func2(2.)?

В случае func1() создание экземпляра, вероятно, происходит с вызовом a1.func1<double>(1.);, так как это первый раз, когда известен второй параметр шаблона T2?

Относительно второстепенного вопроса: имеет ли значение, пишу ли я A или A<T>? Я думаю, что это то же самое, но я не уверен в этом.


person j_d    schedule 16.10.2020    source источник
comment
пожалуйста, по одному вопросу на вопрос.   -  person 463035818_is_not_a_number    schedule 16.10.2020


Ответы (1)


Методы шаблонов классов создаются только при вызове. Для иллюстрации рассмотрим:

#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
}

Создание foo<double> — это нормально. Вы просто не можете вызвать его метод only_for_int. Тот факт, что не каждый метод должен быть валидным, очень удобен для того, чтобы позволить типам, которые не могут поддерживать все требования шаблонов, использовать по крайней мере подмножество методов шаблонов.

person 463035818_is_not_a_number    schedule 16.10.2020
comment
@j_d не совсем уверен, что ты имеешь в виду. Это связано, но я не вижу, что иначе SFINAE был бы невозможен - person 463035818_is_not_a_number; 16.10.2020