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])), и имя имеет связь; или
это безымянный класс или безымянное перечисление, которое является членом класса со связью; или
это 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
Шаблон класса связан с самым внутренним охватывающим классом или пространством имен, в котором он объявлен.