﻿# Linkage

Linkage, или связывание – это свойство идентификатора, позволяющее компилятору в некоторых случаях создавать для нескольких одинаковых имен, объявленных в разных единицах трансляции, одну общую сущность\. Вместе с областью видимости связывание определяет, из каких единиц трансляции и их блоков можно обратиться к сущности\.

Существуют 4 вида связывания: _no linkage_, _internal linkage_, _external linkage_ и _module linkage_\.

## No linkage

Следующие сущности, объявленные в блочной области видимости, имеют _no linkage_ \(иначе говоря, не имеют связывания\):

* Локальные переменные, объявленные без спецификатора _extern_;
* Локальные классы и их методы;
* Другие идентификаторы, кроме имен функций, например псевдонимы или перечисления\.

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

## Internal linkage

Если идентификатор имеет _internal linkage_ \(внутреннее связывание\), то к нему можно обратиться из любого места текущей единицы трансляции\. Для нескольких объявлений одинаковых имен с внутренним связыванием в одной единице трансляции компилятор сгенерирует один объект\. Для одинаковых имен с _internal linkage_ в разных единицах трансляции компилятор создаст разные объекты\.

Следующие сущности, объявленные в пространстве имен, имеют внутреннее связывание:

* Переменные и функции, объявленные со спецификатором _static_;
* Нешаблонные переменные, объявленные со спецификатором _const_ и без спецификаторов _inline_ и _volatile_, а также без _extern\. _Дополнительно такая переменная не должна быть объявлена с external linkage ранее;
* Члены анонимных объединений;
* Любые имена, объявленные в безымянном пространстве имен, в том числе объявленные со спецификатором _extern_\.

## External linkage

Идентификатор, имеющий _external linkage_ \(внешнее связывание\), доступен из других единиц трансляции\. Для одинаковых имен с внешним связыванием компилятор создаст один объект\.

Идентификатор, имеющий _external linkage_, также имеет _language linkage_, благодаря которому связываются юниты трансляции, написанные на разных языках программирования\.

Следующие сущности, объявленные в пространстве имен, имеют _external linkage_:

* Функции без спецификатора _static_;
* Переменные без спецификаторов _const_ и _extern_;
* Переменные со спецификатором _extern_;
* Перечисления;
* Имена классов, их методов, а также вложенные классы и перечисления;
* Функции, объявленные внутри класса со спецификатором _friend_;
* Шаблоны, объявленные со спецификатором _static_, за исключением шаблонов функций и переменных\.

Следующие сущности, объявленные в блочной области видимости, имеют _external linkage_:

* Переменные, объявленные со спецификатором _extern_;
* Функции\.

## Module linkage

Начиная со стандарта C\+\+20, идентификатор может иметь _module linkage_ \(модульное связывание\)\. Такой идентификатор доступен из единиц трансляции, входящих в тот же модуль, в котором он объявлен\. Соответственно, для нескольких одинаковых объявлений одноименных сущностей с _module linkage_ в рамках одного модуля будет создан один объект\.

_Module linkage_ имеют идентификаторы, прикрепленные к именованному модулю и не объявленные с ключевым словом _export_\. Рассмотрим следующий код:

```cpp
// cute_module_main.h
module CuteModule:moduleVariable;

int moduleVariable = 0;

// cute_module_calculator.h
export module CuteModule;

import :moduleVariable;

export int GetSquaredModuleVariable() {
    return ::moduleVariable * ::moduleVariable;
}
```

Здесь переменная _moduleVariable_ имеет _module linkage_\.