Using alias

Директива_using_alias вводит идентификатор, служащий псевдонимом для пространства имен или типа внутри непосредственно вмещающей единицы компиляции или тела пространства имен.

директива_using_alias:
using идентификатор = имя_пространства_имен_или_типа ;

Внутри объявлений членов в единице компиляции или в теле пространства имен, содержащем директиву_using_alias, идентификатор, введенный директивой_using_alias, можно использовать для ссылки на данное пространство имен или тип. Например:

namespace N1.N2
{
class A {}
}

namespace N3
{
using A = N1.N2.A;

class B: A {}
}

В приведенном примере внутри объявлений членов в пространстве имен N3, A является псевдонимом для N1.N2.A, и таким образом класс N3.B является производным от класса N1.N2.A. Такой же результат можно получить, создав псевдоним R для N1.N2 и затем ссылаясь на R.A:

namespace N3
{
using R = N1.N2;

class B: R.A {}
}

Идентификатор в директиве_using_alias должен быть уникальным внутри области объявлений единицы компиляции или пространства имен, непосредственно содержащих директиву_using_alias. Например:

namespace N3
{
class A {}
}

namespace N3
{
using A = N1.N2.A; // Error, A already exists
}

В приведенном примере N3 уже содержит член A, поэтому использование этого идентификатора в директиве_using_alias вызовет ошибку времени компиляции. Аналогично, произойдет ошибка времени компиляции, если две или более директивы_using_alias в одной и той же единице компиляции или пространстве имен объявляют псевдонимы с одним и тем же именем.

Директива_using_alias делает псевдоним доступным внутри отдельной единицы компиляции или тела пространства имен, но не размещает новые члены в базовой области объявлений. Иначе говоря, директива_using_alias не является транзитивной, и влияет только на единицу компиляции или тело пространства имен, в котором находится. В этом примере

namespace N3
{
using R = N1.N2;
}

namespace N3
{
class B: R.A {} // Error, R unknown
}

область директивы_using_alias, которая вводит R, распространяется только на объявления членов в теле пространства имен, в котором она содержится, так что R неизвестно в объявлении второго пространства имен. Однако если поместить директиву_using_alias в содержащую единицу компиляции, то этот псевдоним будет доступен внутри обоих объявлений пространств имен:

using R = N1.N2;

namespace N3
{
class B: R.A {}
}

namespace N3
{
class C: R.A {}
}

Как и регулярные члены, имена, введенные директивой_using_alias, скрыты членами с таким же именем во вложенных областях. В этом примере

using R = N1.N2;

namespace N3
{
class R {}

class B: R.A {} // Error, R has no member A
}

ссылка на R.A в объявлении B приводит к ошибке времени компиляции, так как R ссылается на N3.R, а не на N1.N2.

Порядок, в котором записаны директивы_using_alias, не имеет значения, а на разрешение имени_пространства_имен_или_типа, на которое ссылается директива_using_alias, не влияет ни сама директива_using_alias, ни другие директивы_using в непосредственно содержащей единице компиляции или теле пространства имен. Другими словами, имя_пространства_имен_или_типа директивы_using_alias разрешается, если непосредственно содержащая единица компиляции или тело пространства имен не имеет директивы_using. На директиву_using_alias могут повлиять директивы_extern_alias в непосредственно содержащей единице компиляции или теле пространства имен. В этом примере

namespace N1.N2 {}

namespace N3
{
extern alias E;

using R1 = E.N; // OK

using R2 = N1; // OK

using R3 = N1.N2; // OK

using R4 = R2.N2; // Error, R2 unknown
}

последняя директива_using_alias приводит к ошибке времени компиляции, так как на нее не влияет первая директива_using_alias. Первая директива_using_alias не приводит к ошибке, поскольку область внешнего псевдонима E включает директиву_using_alias.

Директивой_using_alias можно создать псевдоним для любого пространства имен или типа, включая пространство имен, внутри которого она находится, и любое пространство имен или тип, вложенные в это пространство имен.

Доступ к пространству имен или типу через псевдоним дает точно такой же результат, как доступ к этому пространству имен или типу через его объявленное имя. Например, если дана

namespace N1.N2
{
class A {}
}

namespace N3
{
using R1 = N1;
using R2 = N1.N2;

class B
{
N1.N2.A a; // refers to N1.N2.A
R1.N2.A b; // refers to N1.N2.A
R2.A c; // refers to N1.N2.A
}
}

имена N1.N2.A, R1.N2.A и R2.A эквивалентны и все они ссылаются на класс, полное имя которого N1.N2.A.

С помощью псевдонимов можно именовать закрытый сформированный тип, но нельзя именовать объявление несвязанного универсального типа, не предоставляя аргументы типа. Например:

namespace N1
{
class A<T>
{
class B {}
}
}

namespace N2
{
using W = N1.A; // Error, cannot name unbound generic type

using X = N1.A.B; // Error, cannot name unbound generic type

using Y = N1.A<int>; // Ok, can name closed constructed type

using Z<T> = N1.A<T>; // Error, using alias cannot have type parameters
}