Внутри шаблона некоторые конструкции имеют семантику, которая может отличаться от одного экземпляра к другому. Такая конструкция зависит от параметров шаблона. В частности, типы и выражения могут зависеть от типа и / или значения параметров шаблона (как определено аргументами шаблона), и это определяет контекст для поиска имени для определенных имен. Выражения могут быть type-dependent (то есть его тип может зависеть от параметра шаблона) или value-dependent (то есть его значение при оценке как постоянное выражение ([expr.const]) может зависеть от параметра шаблона), как описано в этом подпункте. В выражении формы:
postfix-expression ( expression-listopt )
где postfix-expression является an unqualified-id, unqualified-id обозначает a, dependent name если
любое из выражений в expression-list- это pack expansion,
любое из выражений или braced-init-lists в expression-list естьtype-dependent, или
unqualified-id является , template-idв котором любой из аргументов шаблона зависит от параметра шаблона.
Если операнд оператора является выражением, зависящим от типа, оператор также обозначает зависимое имя. Такие имена не связаны и просматриваются в точке создания экземпляра шаблона ([temp.point]) как в контексте определения шаблона, так и в контексте точки создания экземпляра.
[ Example:
template<class T> struct X : B<T> { typename T::A* pa; void f(B<T>* pb) { static int i = B<T>::i; pb->j++; } };
имя базового класса, имя B<T>типа T::A, имена B<T>::i и pb->j явно зависят от template-parameter. ] — end example
В определении класса или шаблона класса область видимостиdependent base class не проверяется во время неквалифицированного поиска имени ни в точке определения шаблона или члена класса, ни во время создания экземпляра шаблона или члена класса. [ Example:
typedef double A;
template<class T> class B {
typedef int A;
};
template<class T> struct X : B<T> {
A a; // a has type double
};
Имя типа A в определении X<T> связывается с именем typedef, определенным в области глобального пространства имен, а не с именем typedef, определенным в базовом классе B<T>. ] [ — end example Example:
struct A { struct B { /* ... */ }; int a; int Y; }; int a; template<class T> struct Y : T { struct B { /* ... */ }; B b; // The B defined in Y void f(int i) { a = i; } // ::a Y* p; // Y<T> }; Y<A> ya;
Члены A::B, A::aи A::Y аргумента шаблона A не влияют на привязку имен в Y<A>. ] — end example
Имя относится к тому, current instantiation если это
в определении шаблона класса, вложенного класса шаблона класса, члена шаблона класса или члена вложенного класса шаблонаinjected-class-name класса, шаблона класса или вложенного класса,
в определении шаблона первичного класса или члена шаблона первичного класса, имя шаблона класса, за которым следует список аргументов шаблона первичного шаблона (как описано ниже), заключенный в <> (или эквивалентную специализацию псевдонима шаблона),
в определении вложенного класса шаблона класса имя вложенного класса, на который ссылается как на член текущего экземпляра, или
в определении частичной специализации или члена частичной специализации - имя шаблона класса, за которым следует список аргументов шаблона частичной специализации, заключенной в <> (или эквивалентная специализация псевдонима шаблона). Если параметрnth шаблона является пакетом параметров,nаргумент шаблона th является pack expansion шаблоном, шаблон которого является именем пакета параметров.
Список аргументов шаблона первичного шаблона - это список аргументов шаблона, в котором nаргумент th шаблона имеет значение параметра nth шаблона шаблона класса. Еслиnth параметром шаблона является a template parameter pack,nаргумент th шаблона - это a pack expansion , шаблон которого является именем пакета параметров шаблона.
Аргумент шаблона, который эквивалентен параметру шаблона (т. Е. Имеет то же постоянное значение или тот же тип, что и параметр шаблона), может использоваться вместо этого параметра шаблона в ссылке на текущий экземпляр. В случае аргумента шаблона, не являющегося типом, аргументу должно быть задано значение параметра шаблона, а не выражение, в котором параметр шаблона появляется как часть выражения. [ Example:
template <class T> class A { A* p1; // A is the current instantiation A<T>* p2; // A<T> is the current instantiation A<T*> p3; // A<T*> is not the current instantiation ::A<T>* p4; // ::A<T> is the current instantiation class B { B* p1; // B is the current instantiation A<T>::B* p2; // A<T>::B is the current instantiation typename A<T*>::B* p3; // A<T*>::B is not the current instantiation }; }; template <class T> class A<T*> { A<T*>* p1; // A<T*> is the current instantiation A<T>* p2; // A<T> is not the current instantiation }; template <class T1, class T2, int I> struct B { B<T1, T2, I>* b1; // refers to the current instantiation B<T2, T1, I>* b2; // not the current instantiation typedef T1 my_T1; static const int my_I = I; static const int my_I2 = I+0; static const int my_I3 = my_I; B<my_T1, T2, my_I>* b3; // refers to the current instantiation B<my_T1, T2, my_I2>* b4; // not the current instantiation B<my_T1, T2, my_I3>* b5; // refers to the current instantiation };
— end example ]
Adependent base class - это базовый класс, который является зависимым типом и не является текущим экземпляром. [ Note: Базовый класс может быть текущим экземпляром в случае, если вложенный класс называет включающий класс базовым. [ Example:
template<class T> struct A {
typedef int M;
struct B {
typedef void M;
struct C;
};
};
template<class T> struct A<T>::B::C : A<T> {
M m; // OK, A<T>::M
};
— end example ] ] — end note
Имя - это member of the current instantiation если это
Неквалифицированное имя, которое при поиске относится по крайней мере к одному члену класса, который является текущим экземпляром или его независимым базовым классом. [ Note: Это может произойти только при поиске имени в области, содержащейся в определении шаблона класса. ] — end note
A, qualified-id в котором nested-name-specifier относится к текущему экземпляру и который при поиске относится по крайней мере к одному члену класса, который является текущим экземпляром, или его независимым базовым классом. [ Note: Если такой член не найден, а у текущего экземпляра есть какие-либо зависимые базовые классы, то qualified-idэто член неизвестной специализации; см. ниже. ] — end note
id-expressionОбозначая член вclass member access выражении для которого тип выражения объекта является текущим конкретизации, и id-expression, когдаlooked up, относится к по меньшей мере , одного члена класса , который является текущим конкретизации или не зависящих от их базового класса. [ Note: Если такой член не найден, а у текущего экземпляра есть какие-либо зависимые базовые классы, то id-expressionэто член неизвестной специализации; см. ниже. ] — end note
[ Example:
template <class T> class A { static const int i = 5; int n1[i]; // i refers to a member of the current instantiation int n2[A::i]; // A::i refers to a member of the current instantiation int n3[A<T>::i]; // A<T>::i refers to a member of the current instantiation int f(); }; template <class T> int A<T>::f() { return i; // i refers to a member of the current instantiation }
— end example ]
Имя - это,dependent member of the current instantiation если он является членом текущего экземпляра, который при поиске ссылается по крайней мере на один член класса, который является текущим экземпляром.
Имя - это member of an unknown specialization если это
Объект, qualified-id в котором nested-name-specifier именуется зависимый тип, не являющийся текущим экземпляром.
A, qualified-idв котором nested-name-specifier относится к текущему экземпляру, текущий экземпляр имеет по крайней мере один зависимый базовый класс, а поиск имени qualified-idне находит ни одного члена класса, который является текущим экземпляром или его независимым базовым классом.
id-expressionОбозначая член в class member access выражении , в котором либо
тип объектного выражения - это текущая реализация, текущая реализация имеет по крайней мере один зависимый базовый класс, а поиск имени id-expressionне находит члена класса, который является текущим экземпляром, или его независимого базового класса; или
тип объектного выражения является зависимым и не является текущим экземпляром.
Если a, qualified-idв котором nested-name-specifier относится к текущему экземпляру, не является членом текущего экземпляра или элементом неизвестной специализации, программа имеет неправильный формат, даже если шаблон, содержащий элемент, не создается qualified-id; диагностика не требуется. Точно так же, если id-expressionвыражение доступа к члену класса, для которого тип выражения объекта является текущим экземпляром, не относится к члену текущего экземпляра или члену неизвестной специализации, программа имеет неправильный формат, даже если шаблон содержащее выражение доступа к члену не создается; диагностика не требуется. [ Example:
template<class T> class A { typedef int type; void f() { A<T>::type i; // OK: refers to a member of the current instantiation typename A<T>::other j; // error: neither a member of the current instantiation nor // a member of an unknown specialization } };
— end example ]
Если для заданного набора аргументов шаблона создается экземпляр специализации шаблона, который ссылается на член текущего экземпляра с qualified-idвыражением доступа к члену класса or, имя в qualified-idвыражении доступа к члену класса or ищется в экземпляре шаблона. контекст. Если результат этого поиска отличается от результата поиска имени в контексте определения шаблона, поиск имени неоднозначен. [ Example:
struct A { int m; }; struct B { int m; }; template<typename T> struct C : A, T { int f() { return this->m; } // finds A::m in the template definition context int g() { return m; } // finds A::m in the template definition context }; template int C<B>::f(); // error: finds both A::m and B::m template int C<B>::g(); // OK: transformation to class member access syntax // does not occur in the template definition context; see [class.mfct.non-static]
— end example ]
Тип является зависимым, если он
параметр шаблона,
сотрудник неизвестной специализации,
вложенный класс или перечисление, которое является зависимым членом текущего экземпляра,
тип cv-qualified, где cv-unqualified тип является зависимым,
составной тип, созданный из любого зависимого типа,
тип массива, тип элемента которого является зависимым или чья граница (если есть) зависит от значения,
тип функции, спецификация исключения которой зависит от значения,
a, simple-template-id в котором либо имя шаблона является параметром шаблона, либо любой из аргументов шаблона является зависимым типом или выражением, которое зависит от типа или значения, или является расширением пакета [ Note: Сюда входитinjected-class-name шаблон класса, используемый без расширения template-argument-list. ] , или — end note
обозначается , где есть . decltype(expression)expressiontype-dependent
За исключением случаев, описанных ниже, выражение зависит от типа, если какое-либо подвыражение зависит от типа.
Зависит от id-expression типа, если он содержит
identifier , связанный с именем поиска с одним или более деклараций объявлен с зависимым типом,
identifier , связанный с именем поиска с не-типа template-parameter объявлена с типом , который содержитplaceholder type,
identifier, связанный с именем поиска с одним или более деклараций функций членов текущего экземпляра объявленных с типом возвращаемого , который содержит тип заполнителя,
identifier, связанный с именем поиском сstructured binding declaration которого brace-or-equal-initializerявляется типом-зависимым,
identifier __func__, где любая вмещающих функция представляет собой шаблон, член шаблона класса, или общая лямбду,
template-id , что зависит,
a, conversion-function-id который указывает зависимый тип, или
a nested-name-specifier или a, в qualified-id котором упоминается член неизвестной специализации;
или если он называет зависимый член текущего экземпляра, который является статическим элементом данных типа «массив неизвестных границT» для someT ([temp.static]). Выражения следующих форм зависят от типа, только если тип, указанный с помощью type-id, simple-type-specifier или new-type-id является зависимым, даже если любое подвыражение зависит от типа:
simple-type-specifier ( expression-listopt ) ::opt new new-placementopt new-type-id new-initializeropt ::opt new new-placementopt ( type-id ) new-initializeropt dynamic_cast < type-id > ( expression ) static_cast < type-id > ( expression ) const_cast < type-id > ( expression ) reinterpret_cast < type-id > ( expression ) ( type-id ) cast-expression
Выражения следующих форм никогда не зависят от типа (поскольку тип выражения не может быть зависимым):
literal postfix-expression . pseudo-destructor-name postfix-expression -> pseudo-destructor-name sizeof unary-expression sizeof ( type-id ) sizeof ... ( identifier ) alignof ( type-id ) typeid ( expression ) typeid ( type-id ) ::opt delete cast-expression ::opt delete [ ] cast-expression throw assignment-expressionopt noexcept ( expression )
[ Note: Для стандартного библиотечного макросаoffsetofсм[support.types].. ] — end note
Aclass member access expression зависит от типа, если выражение относится к члену текущего экземпляра, а тип указанного члена является зависимым, или если выражение доступа к члену класса относится к члену неизвестной специализации. [ Note: В выражении формы x.y или xp->y типа выражения обычно является тип члена y класса x (или класса, на который указывает xp). Однако, если x или xp относится к зависимому типу, который не является текущим экземпляром, тип y всегда является зависимым. Если x илиxp относится к независимому типу или относится к текущему экземпляру, тип y является типом выражения доступа к члену класса. ] — end note
A braced-init-listзависит от типа, если какой-либо элемент зависит от типа или является расширением пакета.
За исключением описанного ниже, выражение, используемое в контексте, где требуется постоянное выражение, зависит от значения, если какое-либо подвыражение зависит от значения.
An id-expression зависит от значения, если:
это зависит от типа,
это имя параметра шаблона, не являющегося типом,
он называет статический член данных, который является зависимым членом текущего экземпляра и не инициализируется в a member-declarator,
он называет статическую функцию-член, которая является зависимым членом текущего экземпляра, или
это константа литерального типа и инициализируется выражением, зависящим от значения.
Выражения следующей формы зависят от значения, если unary-expressionили expression зависит от типа, или type-id зависит:
sizeof unary-expression sizeof ( type-id ) typeid ( expression ) typeid ( type-id ) alignof ( type-id ) noexcept ( expression )
[ Note: Для стандартного библиотечного макросаoffsetofсм[support.types].. ] — end note
Выражения следующей формы являются значением-зависимой , если либо type-id или simple-type-specifier зависит , или , expression или cast-expression является значением в зависимости от:
simple-type-specifier ( expression-listopt ) static_cast < type-id > ( expression ) const_cast < type-id > ( expression ) reinterpret_cast < type-id > ( expression ) ( type-id ) cast-expression
Выражение формы, в которой имена зависимых членов текущего экземпляра зависят от значения. Выражение вида также является значением-зависимым , если оценивать как успешно , и результат оценки относится к шаблонному объекту , который является объектом с длительностью статической или потоком хранения или функцией - члена.&qualified-idqualified-id&cast-expressioncast-expressioncore constant expression
Не-тип template-argument является зависимым, если его тип является зависимым или константное выражение, которое он задает, зависит от значения.
Кроме того, не-тип template-argument является зависимым, если соответствующий не-тип template-parameter относится к типу ссылки или указателя, а template-argument обозначает или указывает на член текущего экземпляра или член зависимого типа.
Шаблон template-argument является зависимым, если он называет template-parameter или qualified-id относится к члену неизвестной специализации.