Я нахожу это утомительным занятием, и у комитета есть больше таких забав . Поэтому я думаю, что, вероятно, у меня есть некоторые ошибки в ниже. Поэтому, пожалуйста, прочитайте внимательно:)
Третий абзац
Для специализации шаблона класса, специализации шаблона члена класса или специализации для члена класса шаблона класса, если специализация создается неявно, потому что на нее ссылаются из другой специализации шаблона, если контекст, из которого специализация Ссылка зависит от параметра шаблона, и если специализация не была создана до создания экземпляра вмещающего шаблона, точка создания экземпляра находится непосредственно перед точкой создания вмещающего шаблона.
Другими словами, если создается экземпляр шаблона класса или вложенного класса шаблона класса, а контекст, вызывающий создание этого экземпляра, зависит от параметра шаблона, то экземпляр шаблона / вложенного класса создается непосредственно перед точкой создания экземпляра класса. Шаблон, который ссылается на это.
Контекст в другой специализации может зависеть от параметров шаблона, как в случае первичных шаблонов, частичных специализаций и членов шаблона класса, или он не зависит от параметров шаблона, который случай для ссылок изнутри явных специализаций.
В противном случае [т.е. контекст не зависит], точка
создание такой специализации непосредственно предшествует объявлению или определению области пространства имен, относящемуся к специализации.
Это различие важно. Подумайте, что произойдет, если точка создания экземпляров для специализаций из зависимых контекстов будет предшествовать немедленному объявлению или определению области имен пространства имен
template<typename T, int N>
struct A {
typedef typename A<T, N-1>::type *type;
};
template<typename T>
struct A<T, 0> {
typedef T type;
};
typedef A<int, 2>::type ptr;
Этот шаблон должен добавить N
деклараторов указателей. Например, A<int, 2>
равно int**
.
- Контекст вокруг
typedef A<int, 2>::type
не зависит, поэтому A<int, 2>
создается перед объявлением typedef.
В пределах A<int, 2>
у нас есть A<int, N-1>::type
, который появляется в зависимом контексте и который ссылается на A<int, 1>::type
. Таким образом, Стандарт требует от нас создания экземпляра A<int, 1>
в тот же момент, что и экземпляр A<int, 2>
.
Если бы мы создали бы это непосредственно перед объявлением области имен пространства имён, которое ссылалось на него (до определения основного шаблона), мы бы не заметили частичную специализацию A<T, 0>
при обработке `A<int, N-1>::type
в пределах A<int, 1>
потому что мы бы создали A<int, 1>
до этой специализации.
Второй абзац
Это просто для того, чтобы имена, найденные в аргументах по умолчанию, соответствовали именам, найденным в остальной части функции, для которой они используются (т.е. их POI совпадает с POI их шаблона функции / функции-члена класса). шаблон).
Первый абзац
Это в основном то же самое, что и третий абзац. Тем не менее, шаблоны функций создаются после сущности, которая ссылается на них, так что возможно рекурсивное использование, как в следующем примере. Напротив, шаблоны классов создаются перед объектом, который ссылается на них, потому что объект требует, чтобы этот тип класса был завершенным. Если POI типа класса будет после этой сущности, тип класса все равно не будет существовать.
template<typename T>
void f(T);
template<typename T>
struct A {
void g() {
f(0);
}
void h() { /* do a dance */ }
};
template<typename T>
void f(T t) {
A<T> a;
a.h();
}
void g() {
A<int> a;
a.g();
}
Если f
будет создан до A<int>
, то он не сможет получить доступ к a.h()
, поскольку на тот момент он еще не существовал. Поэтому шаблоны функций создаются после сущности, которая на них ссылается, а шаблоны классов создаются перед сущностью, которая на них ссылается.