Попытка понять §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 следует удалить, потому что она ложна.
Ответы
Ответ 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
- конец примера]