6 Basic concepts [basic]

6.5 Program and linkage [basic.link]

A program состоит из одного или нескольких translation units связанных вместе. Единица перевода состоит из последовательности объявлений.

translation-unit:
	declaration-seqopt

Говорят, что имя имеет, linkage когда оно может обозначать тот же объект, ссылку, функцию, тип, шаблон, пространство имен или значение, что и имя, введенное объявлением в другой области:

  • Когда имя имеет external linkage, на объект, который оно обозначает, можно ссылаться по именам из областей действия других единиц перевода или из других областей той же единицы перевода.

  • Когда имя имеет internal linkage, на объект, который оно обозначает, можно ссылаться по именам из других областей в той же единице перевода.

  • Когда имя имеет no linkage, сущность, которую оно обозначает, не может упоминаться по именам из других областей видимости.

Имя, namespace scope имеющее внутреннюю связь, если это имя

  • явно объявленный шаблон переменной, функции или функции static; или,

  • не встроенная переменная энергонезависимого константного типа, которая не объявляется явно и не объявляется extern ранее как имеющая внешнюю связь; или

  • член данных анонимного союза.

Безымянное пространство имен или пространство имен, объявленное прямо или косвенно в безымянном пространстве имен, имеет внутреннюю связь. Все другие пространства имен имеют внешнюю связь. Имя, имеющее область пространства имен, которому не была присвоена внутренняя связь выше, имеет ту же связь, что и включающее пространство имен, если это имя

  • Переменная; или

  • функция; или

  • именованный класс (Clause [class]) или безымянный класс, определенный в объявлении typedef, в котором класс имеет имя typedef для целей связывания ([dcl.typedef]); или

  • именованное enumerationили безымянное перечисление, определенное в объявлении typedef, в котором перечисление имеет имя typedef для целей связывания ([dcl.typedef]); или

  • шаблон.

Кроме того, функция-член, статический член данных, именованный класс или перечисление области класса или безымянный класс или перечисление, определенные в объявлении typedef области класса, так что класс или перечисление имеют имя typedef для целей связывания ([dcl.typedef]), имеет ту же связь, если таковая имеется, что и имя класса, членом которого он является.

Имя функции, объявленной в области видимости блока, и имя переменной, объявленной объявлением области действия блока extern , связаны. Если есть видимое объявление сущности со связью, имеющей то же имя и тип, игнорируя сущности, объявленные вне самой внутренней охватывающей области пространства имен, объявление области блока объявляет ту же самую сущность и получает связь из предыдущего объявления. Если таких совпадающих объектов несколько, программа плохо сформирована. В противном случае, если соответствующая сущность не найдена, сущность области блока получает внешнюю связь. Если внутри единицы трансляции одна и та же сущность объявлена ​​как с внутренней, так и с внешней связью, программа сформирована неправильно. [Example:

static void f();
static int i = 0;               // #1
void g() {
  extern void f();              // internal linkage
  int i;                        // #2: i has no linkage
  {
    extern void f();            // internal linkage
    extern int i;               // #3: external linkage, ill-formed
  }
}

Без объявления в строке №2 объявление в строке №3 будет связано с объявлением в строке №1. Однако, поскольку объявление с внутренней связью скрыто, № 3 дается внешняя связь, что делает программу некорректной. ]end example

Когда в объявлении области блока объекта со связью не обнаружено, что оно ссылается на какое-либо другое объявление, тогда этот объект является членом самого внутреннего включающего пространства имен. Однако такое объявление не вводит имя члена в область его пространства имен. [Example:

namespace X {
  void p() {
    q();                        // error: q not yet declared
    extern void q();            // q is a member of namespace X
  }

  void middle() {
    q();                        // error: q not yet declared
  }

  void q() { /* ... */ }        // definition of X​::​q
}

void q() { /* ... */ }          // some other, unrelated q

end example]

Имена, на которые не распространяются эти правила, не связаны. Более того, если не указано иное, имя, объявленное в, block scope не имеет связи. Говорят, что тип имеет связь тогда и только тогда, когда:

  • это класс или тип перечисления, который имеет имя (или имеет имя для целей связывания ([dcl.typedef])), и имя имеет связь; или

  • это безымянный класс или безымянное перечисление, которое является членом класса со связью; или

  • это специализация шаблона класса (пункт [temp])35; или

  • это fundamental type; или

  • это compound type не класс или перечисление, составленный исключительно из типов, имеющих связь; или

  • это cv-qualified версия типа, имеющего связь.

Тип без связи не должен использоваться как тип переменной или функции с внешней связью, если только

  • объект имеет язык C linkage, или

  • объект объявлен внутри unnamed namespace, или

  • сущность не odr-used определена или определена в той же единице перевода.

[ Note: Другими словами, тип без связи содержит класс или перечисление, которые нельзя назвать вне его единицы перевода. Сущность с внешней связью, объявленная с использованием такого типа, не может соответствовать какой-либо другой сущности в другой единице трансляции программы и, следовательно, должна быть определена в единице трансляции, если она используется odr. Также обратите внимание, что классы со связью могут содержать члены, типы которых не имеют связи, и что имена typedef игнорируются при определении наличия связи у типа. ]end note

[Example:

template <class T> struct B {
  void g(T) { }
  void h(T);
  friend void i(B, T) { }
};

void f() {
  struct A { int x; };  // no linkage
  A a = { 1 };
  B<A> ba;              // declares B<A>​::​g(A) and B<A>​::​h(A)
  ba.g(a);              // OK
  ba.h(a);              // error: B<A>​::​h(A) not defined in the translation unit
  i(ba, a);             // OK
}

end example]

Два имени, которые объявлены the same и объявлены в разных областях, должны обозначать одну и ту же переменную, функцию, тип, шаблон или пространство имен, если

  • оба имени имеют внешнюю связь или оба имени имеют внутреннюю связь и объявлены в одной и той же единице перевода; а также

  • оба имени относятся к членам одного и того же пространства имен или к членам одного и того же класса, но не по наследству; а также

  • когда оба имени обозначают функции, списки типов параметров функций ([dcl.fct]) идентичны; а также

  • когда оба имени обозначают шаблоны функций, подписи ([temp.over.link]) совпадают.

После всех корректировок типов (во время которых typedefs заменяются их определениями) типы, указанные во всех объявлениях, относящихся к данной переменной или функции, должны быть идентичными, за исключением того, что объявления для объекта массива могут указывать типы массивов, которые отличаются наличием или отсутствием основного массива bound ([dcl.array]). Нарушение этого правила для идентификации типа не требует диагностики.

[ Note: Связь с объявлениями, не относящимися к C ++, может быть достигнута с помощью файла linkage-specification. ] end note

Шаблон класса связан с самым внутренним охватывающим классом или пространством имен, в котором он объявлен.