Подтвердить что ты не робот

Попытка понять §3.3.1/4

Как видно из п. 3.3.1/4, этот фрагмент не компилируется, поскольку он содержит два разных объекта с тем же именем A в глобальном пространстве имен, extern int A; и static int A = 101;. То есть, один имеет внешний, а другой имеет внутреннюю связь.

живой пример

#include <iostream>
extern int A;
static int A = 101;
class A{};
int main()
{
    std::cout << A << '\n';
}

Почему же этот код компилируется?

#include <iostream>
static int A = 101;
extern int A;
class A{};
int main()
{
    std::cout << A << '\n';
}

Edit

Я думаю, что принятый ответ на вопрос, из которого этот считается дублированным, в основном говорит о том, что во втором фрагменте переменная A все еще имеет внутреннюю связь, несмотря на объявление extern. Но это не согласуется с параграфом § 3.5/4, о котором я упоминал ниже в комментарии к @dyp.

§ 3.5/4:

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

- переменная; или

...

Изменить 1:

ОП использует §3.5/6, чтобы оправдать свой ответ на другой вопрос.

§3.5/6 (внимание мое):

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

Понятно, что этот ответ не относится к фрагментам, указанным в моем вопросе, поскольку объявления переменной A являются объявлениями не блоков.

Изменить 2:

Эта проблема со статусом "ready" говорит о том, что §7.1.1/7 следует удалить, потому что она ложна.

4b9b3361

Ответ 1

Спецификатор extern не требует, чтобы имя имело внешнюю привязку.

Первый пример

extern int A; является объявлением имени A с внешней связью, но подразумевается внешняя связь, поскольку это объявление в области пространства имен (за пределами неназванного пространства имен).

static int A; объявляет имя с внутренней связью.

Две декларации не согласуются с привязкой, поэтому ошибка.

Второй пример

Здесь мы сначала объявляем static int A;, то есть имя A с внутренней связью.

Объявление extern int A; не объявляет A с внешней связью, оно просто обновляет имя, найденное с помощью поиска по имени.

[dcl.stc]/7

Связи, подразумеваемые последовательными объявлениями для данного объекта соглашается. То есть в рамках данной области каждое декларирование объявления одно и то же имя переменной или же перегрузка имени функции подразумевает ту же связь. Каждая функция в заданном наборе перегруженные функции могут иметь разную связь.

[Пример:

static char* f(); // f() has internal linkage
char* f() // f() still has internal linkage
{ /* ... */ }

char* g(); // g() has external linkage
static char* g() // error: inconsistent linkage
{ /* ... */ }

// [left out some examples with `inline`]

static void n();
inline void n(); // internal linkage

static int a; // a has internal linkage
int a; // error: two definitions

static int b; // b has internal linkage
extern int b; // b still has internal linkage

int c; // c has external linkage
static int c; // error: inconsistent linkage

extern int d; // d has external linkage
static int d; // error: inconsistent linkage

- конец примера]