шаблон функции с неиспользуемым параметром шаблона

template<typename T>
struct a 
{ 
  using type = int;
  typename T::type i;
};

template<typename T, typename = a<T>>
void f1(T) {}

template<typename T, typename = typename a<T>::type>
void f2(T) {}

int main()
{
  f1<int>(1); // ok
  f2<int>(1); // error

  return 0;
}

Создание экземпляра a<int> должно быть ошибкой, потому что int::type является незаконным. Но кажется, что f1<int> не может вызвать создание a<T>, но f2<int> can. Какая причина?

Ответ 1

Когда тип используется как аргумент шаблона (включая аргумент шаблона по умолчанию), он не должен быть полным типом.

Аргумент шаблона для параметра шаблона типа должен быть идентификатором типа, который может называть неполным типом:

Таким образом, для f1 аргумент шаблона по умолчанию является a<T> и он не обязательно должен быть полным. Для f1<int>(1); a<int> не нужно создавать.

Но когда вы ссылаетесь на член шаблона класса, в качестве аргумента шаблона по умолчанию typename a<T>::type of f2, a<T> должен быть полным типом, а затем вызывать неявное создание экземпляра.

Когда код ссылается на шаблон в контексте, который требует полностью определенного типа или когда полнота типа влияет на код, и этот конкретный тип не был явно инстанцирован, происходит неявное создание. Например, когда объект этого типа сконструирован, но не при построении указателя на этот тип.

Это относится к членам шаблона класса: если член не используется в программе, он не создается и не требует определения.

Так что дано f2<int>(1); , a<int> будет a<int> а затем вызывается ошибка компиляции.