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>
Можно. В чем причина?
Когда тип используется в качестве аргумент шаблона (включая аргумент шаблона по умолчанию), необязательно указывать полный тип.
Аргумент шаблона для параметра шаблона типа должен быть идентификатором типа, который может называть неполный тип:
Таким образом, для f1
, аргумент шаблона по умолчанию a<T>
и это не должно быть полным. Дано f1<int>(1);
a<int>
не нужно создавать экземпляры.
Но когда вы ссылаетесь на член шаблона класса, в качестве аргумента шаблона по умолчанию typename a<T>::type
из f2
, a<T>
должен быть полным типом, а затем вызвать неявная реализация.
Когда код ссылается на шаблон в контексте, который требует полностью определенного типа, или когда полнота типа влияет на код, и этот конкретный тип не был явно создан, происходит неявная реализация. Например, когда создается объект этого типа, но не когда создается указатель на этот тип.
Это относится к элементам шаблона класса: если этот элемент не используется в программе, он не создается и не требует определения.
Так дано f2<int>(1);
, a<int>
будет создан, а затем вызовет ошибку компиляции.
Других решений пока нет …