Файлы с расширением
.cpp
обычно являются точками сборки модулей трансляции [
?].
Характеристики связывания имеют свой эффект только между модулями трансляции. Компоновщик занимается связыванием кода и работает с результатами обработки именно модулей трансляции - объектными файлами.
Поэтому, если в одном
.cpp
подключить другой
.cpp
(исключенный из сборки иными способами), то все элементы с внутренним связыванием любого из этих
.cpp
будут доступны в них обоих.
Это будет справедливо и для файлов с расширением
.h
. Файлы
.cpp
обычно включают
.h
и все вместе своим кодом формируют модуль трансляции, в котором доступны все элементы с внутренним связыванием. Даже в коде файлов
.h
.
Это важно учитывать чтобы не совершать некоторых ошибок.
По существу вопроса. Все нестатические (без спецификатора
static
) элементы именованных пространств имен по умолчанию имеют внешнее связывание [
?]. Глобальное пространство является тоже именованным (и доступно через
::
без имени слева) и ровно так же наделяет все свои нестатические элементы характеристикой внешнего связывания.
В противоположность этому, абсолютно все элементы анонимных пространств имен (даже элементы вложенных именованных пространств) имеют характеристику внутреннего связывания [
?].
Довольно распространенной ошибкой является определение анонимных пространств и статических элементов пространств в заголовках, после чего сразу множество модулей трансляции пополняются кодом с внутренним связыванием. Это приводит к разбуханию бинарного кода и усложнению сборки.
Отдельно хотелось бы обозначить
inline
.
Спецификатор
inline
[
?] дает пометку слабого внешнего связывания для любой сущности. Что константа или глобальная переменная, что функция или метод (даже статический), помечаются как сущности с внешним связыванием, которое не нарушает ODR в случае если все определения цели связывания во всех модулях трансляции являются полностью одинаковыми. Если хоть одно определение цели связывания отличается - будет нарушение ODR.
Компоновщик подберет самое первое определение и встроит его в бинарный код. После этого компоновщик будет только проверять другие встреченные определения на предмет соответствия первому, а линковку кода будет производить только относительно первого встреченного определения.
Поэтому, если в любом именованном пространстве, в нескольких
.cpp
определить
inline
функции с одним именем и одной сигнатурой, но разными телами, то проблем со сборкой будет не избежать.
Все это можно более детально изучить в
статье на хабре.