10 Declarations [dcl.dcl]

10.3 Namespaces [basic.namespace]

10.3.1 Namespace definition [namespace.def]

namespace-name:
	identifier
	namespace-alias
namespace-definition:
	named-namespace-definition
	unnamed-namespace-definition
	nested-namespace-definition
named-namespace-definition:
	inlineopt namespace attribute-specifier-seqopt identifier { namespace-body }
unnamed-namespace-definition:
	inlineopt namespace attribute-specifier-seqopt { namespace-body }
nested-namespace-definition:
	namespace enclosing-namespace-specifier :: identifier { namespace-body }
enclosing-namespace-specifier:
	identifier
	enclosing-namespace-specifier :: identifier
namespace-body:
	declaration-seqopt

Каждый namespace-definitionдолжен появиться в глобальной области видимости или в области видимости пространства имен ([basic.scope.namespace]).

В named-namespace-definition, то identifierэто имя пространства имен. Если identifierпри поиске ([basic.lookup.unqual]) относится к namespace-name(но не a namespace-alias), которое было введено в пространство имен, в котором named-namespace-definitionпоявляется, или которое было введено в члене встроенного набора пространств имен этого пространства имен, namespace-definition extends ранее объявленное пространство имен. В противном случае identifierвводится как namespace-nameв декларативную область, в которой named-namespace-definitionпоявляется.

Поскольку a namespace-definitionсодержится declarations в его, namespace-bodyа a namespace-definitionсамо является a declaration, отсюда следует, что он namespace-definitions может быть вложенным. [Example:

namespace Outer {
  int i;
  namespace Inner {
    void f() { i++; }           // Outer​::​i
    int i;
    void g() { i++; }           // Inner​::​i
  }
}

end example]

Объектамиenclosing namespaces объявления являются те пространства имен, в которых объявление появляется лексически, за исключением повторного объявления члена пространства имен вне его исходного пространства имен (например, определения, как указано в[namespace.memdef]). Такое повторное объявление имеет те же охватывающие пространства имен, что и исходное объявление. [Example:

namespace Q {
  namespace V {
    void f();                   // enclosing namespaces are the global namespace, Q, and Q​::​V
    class C { void m(); };
  }
  void V::f() {                 // enclosing namespaces are the global namespace, Q, and Q​::​V
    extern void h();            // ... so this declares Q​::​V​::​h
  }
  void V::C::m() {              // enclosing namespaces are the global namespace, Q, and Q​::​V
  }
}

end example]

Если необязательное начальноеinline ключевое слово появляется в a namespace-definitionдля определенного пространства имен, это пространство имен объявляетсяinline namespace.inline Ключевое слово может быть использовано на namespace-definitionкоторый расширяет пространство имен , только если он был ранее использован на namespace-definition том , что изначально объявлено namespace-nameдля этого пространства имен.

Необязательный параметр attribute-specifier-seq в a named-namespace-definition принадлежит определяемому или расширяемому пространству имен.

Члены встроенного пространства имен можно использовать во многих отношениях, как если бы они были членами включающего пространства имен. В частности, встроенное пространство имен и его включающее пространство имен добавляются к набору связанных пространств имен, используемых argument-dependent lookup всякий раз, когда одно из них есть, а элемент, using-directiveкоторый именует встроенное пространство имен, неявно вставляется во включающее пространство имен, как дляunnamed namespace. Кроме того, каждый член инлайн пространства имен может впоследствии бытьpartially specialized,explicitly instantiatedили ,explicitly specialized как если бы она была членом пространства имен вмещающих. Наконец, поиск имени в охватывающем пространстве имен с помощью явной qualification ([namespace.qual]) будет включать элементы встроенного пространства имен, внесенных с помощью, using-directiveдаже если есть объявления этого имени во включающем пространстве имен.

Эти свойства являются транзитивными: если пространство именN содержит встроенное пространство имен M, которое, в свою очередь, содержит встроенное пространство именO, тогда члены O могут использоваться, как если бы они были членамиM илиN.inline namespace set ИзN является транзитивным замыканием всех встроенных пространств имен вN.enclosing namespace set ИзO есть множество пространств имен , состоящие из самих внутренних без встроенного пространства имен , охватывающего инлайн пространства именO, вместе с любыми промежуточным инлайн пространствами имен.

A nested-namespace-definitionс символом enclosing-namespace-specifierE, identifierI и namespace-bodyB эквивалентно

namespace E { namespace I { B } }

[Example:

namespace A::B::C {
  int i;
}

Вышеупомянутое имеет тот же эффект, что и:

namespace A {
  namespace B {
    namespace C {
      int i;
    }
  }
}

end example]

10.3.1.1 Unnamed namespaces [namespace.unnamed]

Ведет unnamed-namespace-definitionсебя так, как если бы его заменили на

inlineopt namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }

где inline появляется тогда и только тогда, когда он появляется в unnamed-namespace-definition и все вхожденияunique в единицу перевода заменяются одним и тем же идентификатором, и этот идентификатор отличается от всех других идентификаторов в единице перевода. Опциональная attribute-specifier-seq в unnamed-namespace-definition appertains кunique. [Example:

namespace { int i; }            // unique​::​i
void f() { i++; }               // unique​::​i++

namespace A {
  namespace {
    int i;                      // A​::​unique​::​i
    int j;                      // A​::​unique​::​j
  }
  void g() { i++; }             // A​::​unique​::​i++
}

using namespace A;
void h() {
  i++;                          // error: unique​::​i or A​::​unique​::​i
  A::i++;                       // A​::​unique​::​i
  j++;                          // A​::​unique​::​j
}

end example]

10.3.1.2 Namespace member definitions [namespace.memdef]

Объявление в пространстве именN (за исключением объявлений во вложенных областях), declarator-idкоторое является unqualified-id([dcl.meaning]), class-head-nameили enum-head-nameявляется identifier, или elaborated-type-specifierимеет форму ( ), или это , объявляет (или повторно объявляет) его или в качестве члена . [ Или шаблон не ввести имя и , таким образом , может быть объявлено используя в качестве члена множества вшито пространства имен, если основной шаблон объявлен в инлайн пространстве имен. ] [class-key attribute-specifier-seqopt identifier[dcl.type.elab]opaque-enum-declarationunqualified-ididentifierNNote: explicit instantiation explicit specialization unqualified-idend noteExample:

namespace X {
  void f() { /* ... */ }        // OK: introduces X​::​f()

  namespace M {
    void g();                   // OK: introduces X​::​M​::​g()
  }
  using M::g;
  void g();                     // error: conflicts with X​::​M​::​g()
}

end example]

Члены именованного пространства имен также могут быть определены вне этого пространства имен с помощью явной qualification ([namespace.qual]) определяемого имени при условии, что определяемая сущность уже была объявлена ​​в пространстве имен и определение появляется после точки объявления в пространстве имен, которое включает пространство имен декларации. [Example:

namespace Q {
  namespace V {
    void f();
  }
  void V::f() { /* ... */ }     // OK
  void V::g() { /* ... */ }     // error: g() is not yet a member of V
  namespace V {
    void g();
  }
}

namespace R {
  void Q::V::g() { /* ... */ }  // error: R doesn't enclose Q
}

end example]

Еслиfriend объявление в нелокальном классе сначала объявляет класс, функцию, шаблон класса или шаблон функции,97 то друг является членом самого внутреннего включающего пространства имен.friend Декларация сама по себе не делает имя видимым для неквалифицированного поиска ([basic.lookup.unqual]) или квалифицированного поиска ([basic.lookup.qual]). [ Note: Имя друга будет видно в его пространстве имен, если соответствующее объявление предоставлено в области пространства имен (либо до, либо после определения класса, предоставляющего дружбу). ] Если вызывается дружественная функция или шаблон функции, ее имя можно найти с помощью поиска по именам, который рассматривает функции из пространств имен и классов, связанных с типами аргументов функции ( ). Если имя в объявлении не является ни квалифицированным, ни a, а объявление является функцией или объектом, поиск для определения того, была ли объект объявлен ранее, не должен учитывать какие-либо области за пределами самого внутреннего включающего пространства имен. [ Другие формы объявлений не могут объявлять новый член самого внутреннего включающего пространства имен и, таким образом, следовать обычным правилам поиска. ] [end note[basic.lookup.argdep]friend template-idelaborated-type-specifierNote: friend end noteExample:

// Assume f and g have not yet been declared.
void h(int);
template <class T> void f2(T);
namespace A {
  class X {
    friend void f(X);           // A​::​f(X) is a friend
    class Y {
      friend void g();          // A​::​g is a friend
      friend void h(int);       // A​::​h is a friend
                                // ​::​h not considered
      friend void f2<>(int);    // ​::​f2<>(int) is a friend
    };
  };

  // A​::​f, A​::​g and A​::​h are not visible here
  X x;
  void g() { f(x); }            // definition of A​::​g
  void f(X) { /* ... */ }       // definition of A​::​f
  void h(int) { /* ... */ }     // definition of A​::​h
  // A​::​f, A​::​g and A​::​h are visible here and known to be friends
}

using A::x;

void h() {
  A::f(x);
  A::X::f(x);                   // error: f is not a member of A​::​X
  A::X::Y::g();                 // error: g is not a member of A​::​X​::​Y
}

end example]

это означает, что имя класса или функции неквалифицировано.