Объявление локальной внешней переменной с директивой использования в ближайшей охватывающей области

Правильно ли построена эта программа в соответствии со стандартом С++?

namespace X { int i = 1; }

using namespace X;

int main() {
    extern int i;
    i = 2;
}

Я получаю разные результаты с разными компиляторами:

  • GCC и Clang выдают ошибку компоновщика: Неопределенная ссылка на i.

  • Visual C++ принимает программу.


person Supremum    schedule 18.07.2015    source источник
comment
Clang и GCC принять программу. Какие версии вы используете?   -  person 0x499602D2    schedule 18.07.2015
comment
Последняя возможная версия здесь: melpon.org/wandbox   -  person Supremum    schedule 18.07.2015
comment
У меня была ошибка в примере. Я исправил это сейчас. Теперь и GCC, и Clang выдают ошибку компиляции (неопределенная ссылка на i).   -  person Supremum    schedule 18.07.2015
comment
Я имел в виду ошибку компоновщика вместо ошибки компилятора в моем предыдущем комментарии.   -  person Supremum    schedule 18.07.2015


Ответы (1)


[основная.ссылка]/p6:

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

X::i было объявлено за пределами самого внутреннего окружающего пространства имен объявления extern (т. е. глобального пространства имен), поэтому оно игнорируется. Это означает, что объявление для i не найдено, и поэтому extern int i является объявлением новой переменной с именем i с внешней связью.

Ваша программа будет скомпилирована, но не будет компоноваться, если область действия блока i используется odr.

person 0x499602D2    schedule 18.07.2015
comment
Не [namespace.udir]p2 ( eel.is/c++draft/ namespace.udir#2 ) применить здесь? - person Supremum; 18.07.2015
comment
@Supremum Меня это тоже беспокоило, но я думаю, что из этой заметки из [basic.scope.pdecl]/p11 объявления функций в области блока и объявления переменных со спецификатором extern в области блока относятся к объявлениям, которые являются членами охватывающего пространство имен, X::i выглядит так, как если бы оно было объявлено в глобальном пространстве имен, но не является членом, что исключает его из поиска. Я немного шатаюсь в этой области, так что, может быть, кто-то более знающий придет с чем-то окончательным. - person 0x499602D2; 18.07.2015
comment
Хм... Да, X::i явно не является членом глобального пространства имен, так как он там не объявлен, но, согласно [namespace.udir]p2, поиск имен должен вести себя так, как будто он был объявлен там, и, следовательно, был членом глобальное пространство имен. Однако я думаю, что применение [basic.link]/p6 не является поиском имени. Поэтому я думаю, что вы правы в том, что здесь мы должны получить ошибку компоновщика. Означает ли это, что в Visual С++ есть ошибка, из-за которой не сообщается об ошибке компоновщика? - person Supremum; 18.07.2015
comment
@Supremum Да, я думаю, что у VC ++ здесь есть ошибка. - person 0x499602D2; 18.07.2015
comment
@ 0x499602D2 Я бы подумал, что изменение using namespace X; на using X::i; скомпилируется. Это тоже не удается, хотя этот ответ, кажется, указывает на то, что использование декларация равнозначна декларации в том же регионе для этой сущности. Я не понимаю, почему это все еще терпит неудачу, поскольку их объявление явно видно. - person Colin Hicks; 27.01.2021