В определении шаблона можно использовать три вида имен:
Имя самого шаблона и имена, объявленные в самом шаблоне.
Имена, зависящие от template-parameter([temp.dep]).
Имена из областей видимости в определении шаблона.
Предполагается, что имя, используемое в объявлении или определении шаблона и зависящее от a, template-parameter не именует тип, если только применимый поиск имени не найдет имя типа или имя не уточнено ключевым словом typename. [ Example:
// no B declared here class X; template<class T> class Y { class Z; // forward declaration of member class void f() { X* a1; // declare pointer to X T* a2; // declare pointer to T Y* a3; // declare pointer to Y<T> Z* a4; // declare pointer to Z typedef typename T::A TA; TA* a5; // declare pointer to T's A typename T::A* a6; // declare pointer to T's A T::A* a7; // T::A is not a type name: // multiplication of T::A by a7; ill-formed, no visible declaration of a7 B* a8; // B is not a type name: // multiplication of B by a8; ill-formed, no visible declarations of B and a8 } };
— end example ]
Если a qualified-idпредназначен для ссылки на тип, который не является членом текущего экземпляра ([temp.dep.type]), и nested-name-specifier относится к зависимому типу, он должен иметь префикс в виде ключевого слова typename, образующего typename-specifier. Если qualified-idв a typename-specifier не обозначен тип или шаблон класса, программа имеет неправильный формат.
typename-specifier: typename nested-name-specifier identifier typename nested-name-specifier templateopt simple-template-id
Если специализация шаблона создается для набора template-arguments таких, что qualified-id префикс typename не обозначает тип или шаблон класса, специализация сформирована неправильно. Обычный qualified name lookup используется для поиска qualified-id даже при наличии typename. [ Example:
struct A { struct X { }; int X; }; struct B { struct X { }; }; template<class T> void f(T t) { typename T::X x; } void foo() { A a; B b; f(b); // OK: T::X refers to B::X f(a); // error: T::X refers to the data member A::X not the struct A::X }
— end example ]
Полное имя, используемое в качестве имени в a class-or-decltype или an elaborated-type-specifier , неявно предполагается для наименования типа без использования typename ключевого слова. В, nested-name-specifierкоторый непосредственно содержит, nested-name-specifier который зависит от параметра шаблона, неявно предполагается , что identifierили simple-template-idдля имени типа, без использования typename ключевого слова. [ Ключевое слово не допускается синтаксисом этих конструкций. ] Note: typename — end note
Если для заданного набора аргументов шаблона создается экземпляр специализации шаблона, который ссылается на a, qualified-id который обозначает тип или шаблон класса, и qualified-idссылается на член неизвестной специализации, то qualified-idдолжен быть либо предварен префиксом, typename либо должен быть используется в контексте, в котором он неявно называет тип, как описано выше. [ Example:
template <class T> void f(int i) { T::x * i; // T::x must not be a type } struct Foo { typedef int x; }; struct Bar { static int const x = 5; }; int main() { f<Bar>(1); // OK f<Foo>(1); // error: Foo::x is a type }
— end example ]
В определении шаблона класса или в определении члена шаблона класса, следующего за declarator-id, ключевое слово typename не требуется при ссылке на имя ранее объявленного члена шаблона класса, который объявляет тип или шаблон класса. [ Note: Такие имена можно найти с помощью функции unqualified name lookupпоиска члена класса ([class.qual]) в current instantiationвыражении доступа к члену класса или поиска ([basic.lookup.classref]), когда тип выражения объекта является текущим экземпляром ([temp.dep.expr]). ] [ — end note Example:
template<class T> struct A {
typedef int B;
B b; // OK, no typename required
};
— end example ]
Зная, какие имена являются именами типов, можно проверить синтаксис каждого шаблона. Программа составлена неправильно, диагностика не требуется, если:
никакая допустимая специализация не может быть сгенерирована для шаблона или части constexpr if оператора в шаблоне, и шаблон не создается, или
для каждой допустимой специализации вариативного шаблона требуется пустой пакет параметров шаблона, или
гипотетическая реализация шаблона сразу после его определения будет неправильно сформирована из-за конструкции, которая не зависит от параметра шаблона, или
интерпретация такой конструкции в гипотетическом экземпляре отличается от интерпретации соответствующей конструкции в любом фактическом создании экземпляра шаблона. [ Note: Это может произойти в следующих ситуациях:
тип, используемый в независимом имени, является неполным в точке, в которой определен шаблон, но завершен в точке, в которой выполняется создание экземпляра, или
поиск имени в определении шаблона нашел a using-declaration, но поиск в соответствующей области в экземпляре не нашел никаких объявлений, потому что это using-declaration было расширение пакета, а соответствующий пакет пуст, или
создание экземпляра использует аргумент по умолчанию или аргумент шаблона по умолчанию, который не был определен в точке, в которой был определен шаблон, или
constant expression evaluation в экземпляре шаблона использует
значение const объекта целочисленного или перечислимого типа без области видимости, или
стоимость constexpr объекта или
значение ссылки или
определение функции constexpr,
и этот объект не был определен при определении шаблона, или
специализация шаблона класса или специализация шаблона переменной, которая указана независимым simple-template-id, используется шаблоном, и либо он создается из частичной специализации, которая не была определена при определении шаблона, либо он называет явную специализацию, которая не была объявлена когда шаблон был определен.
— end note ]
В противном случае для шаблона, для которого может быть сгенерирована действительная специализация, не будет выдаваться никакая диагностика. [ Note: Если создается экземпляр шаблона, ошибки будут диагностироваться в соответствии с другими правилами этого международного стандарта. Когда именно диагностируются эти ошибки, возникает проблема качества реализации. ] [ — end note Example:
int j; template<class T> class X { void f(T t, int i, char* p) { t = i; // diagnosed if X::f is instantiated, and the assignment to t is an error p = i; // may be diagnosed even if X::f is not instantiated p = j; // may be diagnosed even if X::f is not instantiated } void g(T t) { +; // may be diagnosed even if X::g is not instantiated } }; template<class... T> struct A { void operator++(int, T... t); // error: too many parameters }; template<class... T> union X : T... { }; // error: union with base class template<class... T> struct A : T..., T... { }; // error: duplicate base class
— end example ]
При поиске объявления имени, используемого в определении шаблона, обычные правила поиска ([basic.lookup.unqual], [basic.lookup.argdep]) используются для независимых имен. Поиск имен, зависящих от параметров шаблона, откладывается до тех пор, пока не станет известен фактический аргумент шаблона ([temp.dep]). [ Example:
#include <iostream> using namespace std; template<class T> class Set { T* p; int cnt; public: Set(); Set<T>(const Set<T>&); void printall() { for (int i = 0; i<cnt; i++) cout << p[i] << '\n'; } };
в примере i - это локальная переменная, i объявленная в printall, cnt это член, cnt объявленный в Set, и cout это стандартный поток вывода, объявленный в iostream. Однако не все объявления можно найти таким образом; разрешение некоторых имен должно быть отложено до тех пор, пока не template-arguments станут известны действительные . Например, даже несмотря на то, что имя operator<< известно в определении, printall() и его объявление можно найти в <iostream>, фактическое объявление, operator<< необходимое для печати, p[i] не может быть известно, пока не станет известно, что это за тип T ([temp.dep]). ] — end example
Если имя не зависит от template-parameter (как определено в [temp.dep]), объявление (или набор объявлений) для этого имени должно быть в области видимости в точке, где имя появляется в определении шаблона; имя привязано к объявлению (или объявлениям), найденному в этой точке, и на эту привязку не влияют объявления, видимые в момент создания экземпляра. [ Example:
void f(char); template<class T> void g(T t) { f(1); // f(char) f(T(1)); // dependent f(t); // dependent dd++; // not dependent; error: declaration for dd not found } enum E { e }; void f(E); double dd; void h() { g(e); // will cause one call of f(char) followed by two calls of f(E) g('a'); // will cause three calls of f(char) }
— end example ]
[ Note: В целях поиска имени аргументы по умолчанию, а также noexcept-specifiers шаблоны функций, аргументы по умолчанию и noexcept-specifiers функции-члены шаблонов классов считаются определениями ([temp.decls]). ] — end note
Как и обычные (не шаблонные) классы, шаблоны классов имеют расширение injected-class-name. Введенное-имя-класса может использоваться как template-nameили type-name. Когда он используется с template-argument-list, как template-argumentдля шаблона template-parameterили как окончательный идентификатор в elaborated-type-specifierобъявлении шаблона дружественного класса, он ссылается на сам шаблон класса. В противном случае, это равносильно тому , template-name сопровождаемое template-parameters шаблон класса , заключенном в <>.
В рамках специализации шаблона класса или частичной специализации, когда имя injected-class-name используется как a type-name, оно эквивалентно, за template-nameкоторым следует template-arguments специализация шаблона класса или частичная специализация, заключенная в <>. [ Example:
template<template<class> class T> class A { }; template<class T> class Y; template<> class Y<int> { Y* p; // meaning Y<int> Y<char>* q; // meaning Y<char> A<Y>* a; // meaning A<::Y> class B { template<class> friend class Y; // meaning ::Y }; };
— end example ]
Нагнетаемого класса имя шаблона класса или класса специализации шаблона может быть использован либо как template-nameили type-name там , где она находится в области видимости. [ Example:
template <class T> struct Base { Base* p; }; template <class T> struct Derived: public Base<T> { typename Derived::Base* p; // meaning Derived::Base<T> }; template<class T, template<class> class U = T::template Base> struct Third { }; Third<Base<int> > t; // OK: default argument uses injected-class-name as a template
— end example ]
Поиск, который находит внедренное имя-класса ([class.member.lookup]), в некоторых случаях может привести к неоднозначности (например, если он найден более чем в одном базовом классе). Если все найденные имена внедренных классов относятся к специализациям одного и того же шаблона класса, и если имя используется как a template-name, ссылка относится к самому шаблону класса, а не к его специализации, и не является двусмысленной. [ Example:
template <class T> struct Base { }; template <class T> struct Derived: Base<int>, Base<char> { typename Derived::Base b; // error: ambiguous typename Derived::Base<double> d; // OK };
— end example ]
Когда используется обычное имя шаблона (т. Е. Имя из охватывающей области, а не внедренное имя-класса), оно всегда относится к самому шаблону класса, а не к его специализации. [ Example:
template<class T> class X { X* p; // meaning X<T> X<T>* p2; X<int>* p3; ::X* p4; // error: missing template argument list // ::X does not refer to the injected-class-name };
— end example ]
A template-parameter не следует повторно объявлять в пределах своей области действия (включая вложенные области действия). Имя A template-parameter не должно совпадать с именем шаблона. [ Example:
template<class T, int i> class Y { int T; // error: template-parameter redeclared void f() { char T; // error: template-parameter redeclared } }; template<class X> class X; // error: template-parameter redeclared
— end example ]
В определении члена шаблона класса, который появляется вне определения шаблона класса, имя члена шаблона класса скрывает имя template-parameter любого включающего шаблона класса (но не template-parameterчлена, если член является шаблон класса или функции). [ Example:
template<class T> struct A { struct B { /* ... */ }; typedef void C; void f(); template<class U> void g(U); }; template<class B> void A<B>::f() { B b; // A's B, not the template parameter } template<class B> template<class C> void A<B>::g(C) { B b; // A's B, not the template parameter C c; // the template parameter C, not A's C }
— end example ]
В определении члена шаблона класса, который появляется за пределами пространства имен, содержащего определение шаблона класса, имя template-parameter скрывает имя члена этого пространства имен. [ Example:
namespace N {
class C { };
template<class T> class B {
void f(T);
};
}
template<class C> void N::B<C>::f(C) {
C b; // C is the template parameter, not N::C
}
— end example ]
В определении шаблона класса или в определении члена такого шаблона, который появляется вне определения шаблона, для каждого независимого базового класса ([temp.dep.type]), если имя базового класса или имя члена базовый класс такой же , как название template-parameter, имя базового класса или члена имя hides на template-parameter имя. [ Example:
struct A { struct B { /* ... */ }; int a; int Y; }; template<class B, class a> struct X : A { B b; // A's B a b; // error: A's a isn't a type name };
— end example ]
Внутри шаблона некоторые конструкции имеют семантику, которая может отличаться от одного экземпляра к другому. Такая конструкция зависит от параметров шаблона. В частности, типы и выражения могут зависеть от типа и / или значения параметров шаблона (как определено аргументами шаблона), и это определяет контекст для поиска имени для определенных имен. Выражения могут быть 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 ]
A dependent 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)expression type-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» для some T ([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
A class 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-expression core constant expression
Не-тип template-argument является зависимым, если его тип является зависимым или константное выражение, которое он задает, зависит от значения.
Кроме того, не-тип template-argument является зависимым, если соответствующий не-тип template-parameter относится к типу ссылки или указателя, а template-argument обозначает или указывает на член текущего экземпляра или член зависимого типа.
Шаблон template-argument является зависимым, если он называет template-parameter или qualified-id относится к члену неизвестной специализации.
Независимые имена, используемые в определении шаблона, обнаруживаются с помощью обычного поиска по именам и привязываются к месту их использования. [ Example:
void g(double); void h(); template<class T> class Z { public: void f() { g(1); // calls g(double) h++; // ill-formed: cannot increment function; this could be diagnosed // either here or at the point of instantiation } }; void g(int); // not in scope at the point of the template definition, not considered for the call g(1)
— end example ]
При разрешении зависимых имен учитываются имена из следующих источников:
Объявления, которые видны в момент определения шаблона.
Объявления из пространств имен, связанных с типами аргументов функции, как из контекста создания ([temp.point]), так и из контекста определения.
Для специализации шаблона функции, специализации шаблона функции-члена или специализации для функции-члена или статического члена данных шаблона класса, если специализация создается неявно, поскольку на нее имеется ссылка из другой специализации шаблона и контекста, из которого она указанная ссылка зависит от параметра шаблона, точка создания экземпляра специализации - это точка создания экземпляра включающей специализации. В противном случае точка создания такой специализации следует сразу за объявлением или определением области пространства имен, которое ссылается на специализацию.
Если шаблон функции или функция-член шаблона класса вызывается способом, который использует определение аргумента по умолчанию для этого шаблона функции или функции-члена, точкой создания экземпляра аргумента по умолчанию является точка создания экземпляра шаблона функции или специализация функций-членов.
Для noexcept-specifierспециализации шаблона функции или специализации функции-члена в шаблоне класса, если noexcept-specifierнеявно создается экземпляр, потому что он необходим другой специализации шаблона, и контекст, который требует этого, зависит от параметра шаблона, точкой создания экземпляра noexcept-specifierявляется точка реализации требуемой специализации. В противном случае точка создания такого объекта noexcept-specifierсразу следует за объявлением или определением области пространства имен, для которых требуется noexcept-specifier.
Для специализации шаблона класса, специализации шаблона члена класса или специализации для члена класса шаблона класса, если специализация создается неявно, потому что на нее ссылаются из другой специализации шаблона, если контекст, из которого делается ссылка на специализацию, зависит в параметре шаблона, и если специализация не создается до создания экземпляра включающего шаблона, точка создания экземпляра находится непосредственно перед точкой создания экземпляра включающего шаблона. В противном случае точка создания такой специализации непосредственно предшествует объявлению или определению области пространства имен, которое ссылается на специализацию.
Если виртуальная функция создается неявно, ее точка создания экземпляра следует сразу же за точкой создания экземпляра ее специализации шаблона включающего класса.
Явное определение экземпляра - это точка создания экземпляра для специализации или специализаций, указанных с помощью явного создания экземпляра.
Контекст создания выражения, который зависит от аргументов шаблона, представляет собой набор объявлений с внешней связью, объявленных до момента создания экземпляра специализации шаблона в той же единице преобразования.
Специализация для шаблона функции, шаблона функции-члена или функции-члена или статического члена данных шаблона класса может иметь несколько точек создания экземпляров в единице перевода, и в дополнение к точкам создания экземпляров, описанным выше, для любых таких специализации, которая имеет точку создания в пределах единицы перевода, конец единицы трансляции также считается точкой создания экземпляра. Специализация для шаблона класса имеет не более одной точки создания экземпляра в единице перевода. Специализация для любого шаблона может иметь точки реализации в нескольких единицах перевода. Если две разные точки создания экземпляра придают специализации шаблона разные значения в зависимости от one-definition rule, программа имеет неправильный формат и диагностика не требуется.
Для вызова функции, где postfix-expression- зависимое имя, функции-кандидаты находятся с использованием обычных правил поиска ([basic.lookup.unqual], [basic.lookup.argdep]), за исключением того, что:
Для части использования поиска unqualified name lookupнайдены только объявления функций из контекста определения шаблона.
Для части поиска с использованием связанных пространств имен ([basic.lookup.argdep]) обнаруживаются только объявления функций, найденные либо в контексте определения шаблона, либо в контексте создания экземпляра шаблона.
Если вызов был бы неправильно сформирован или нашел бы лучшее совпадение, если бы при поиске в связанных пространствах имен учитывались все объявления функций с внешней связью, введенные в этих пространствах имен во всех единицах перевода, а не только с учетом этих объявлений, найденных в определении шаблона и шаблоне контекстов создания экземпляров, тогда программа имеет неопределенное поведение.
Дружественные классы или функции могут быть объявлены в шаблоне класса. Когда создается экземпляр шаблона, имена его друзей обрабатываются так, как если бы специализация была явно объявлена в точке создания экземпляра.
Как и в случае с классами, не являющимися шаблонами, имена дружественных функций области видимости пространства имен специализации шаблона класса не видны во время обычного поиска, если явно не объявлены в области видимости пространства имен ([class.friend]). Такие имена можно найти в правилах для связанных классов ([basic.lookup.argdep]).140 [ Example:
template<typename T> struct number { number(int); friend number gcd(number x, number y) { return 0; }; }; void g() { number<double> a(3), b(4); a = gcd(a,b); // finds gcd because number<double> is an associated class, // making gcd visible in its namespace (global scope) b = gcd(3,4); // ill-formed; gcd is not visible }
— end example ]
Объявления друзей не вводят новые имена ни в какую область видимости ни при объявлении шаблона, ни при его создании.