Первый фрагмент ниже компилируется, а второй - нет. Зачем? - программирование
Подтвердить что ты не робот

Первый фрагмент ниже компилируется, а второй - нет. Зачем?

Ниже фрагмент ниже компилируется (демонстрация):

struct A{ int i = 10; };

int main() {
    struct A{ int i = 20; };
    struct A;
    struct A a;
}

Но это не так:

struct A{ int i = 10; };

int main() {
//    struct A{ int i = 20; };
    struct A;
    struct A a;
}

Я вижу, что ответ, вероятно, приведен в этих параграфах в стандарте:

[basic.lookup.elab]/2 и [basic.scope.pdecl]/7.

Но я действительно не знаю, как вывести различные поведения, показанные выше из этих двух абзацев.

Обратите внимание, что в первом примере struct A не сначала объявлен в спецификаторе специфицированного типа struct A;, а в определении struct A в main().

Во втором примере struct A также не сначала объявлен в специфицированном спецификаторе типа struct A;, а в определении struct A в глобальной области.

4b9b3361

Ответ 1

Каждый из примеров содержит декларации двух разных классов, как с именем A.

Разделите классы, переименовав один из них в B:

struct A{ int i = 10; };

int main() {
    struct B{ int i = 20; };
    struct B;
    struct B b;
}

Вышеприведенное семантически идентично первому примеру. Класс A никогда не используется.

struct A{ int i = 10; };

int main() {
    struct B;
    struct B b;
}

Это семантически идентично вашему второму примеру. Вы пытаетесь создать объект неполного типа, объявленный вперед класс B.

Переименование B назад на A ничего не меняет, потому что объявление A в main затеняет объявление другого A в глобальной области.

[basic.lookup.elab]/2

Если специфицированный тип-спецификатор не имеет спецификатора вложенных имен и [...], если специфицированный спецификатор типа появляется в объявлении с формой:

class-key attribute-specifier-seq optidentifier ;

специфицированный спецификатор типа - это объявление, которое вводит имя класса, как описано в [basic.scope.pdecl].

Итак struct A; является объявлением , которое вводит имя класса в области объявления. Ни при каких обстоятельствах он не может ссылаться на класс, объявленный во внешней области.

[basic.scope.pdecl]/7

[Примечание. Другие формы специфицированного спецификатора типа не объявляют новое имя [...] - примечание к концу]

По своей сути эта форма специфицированного спецификатора типа объявляет новое имя.

Ответ 2

Во втором примере строка struct A; является прямым объявлением для структуры A в области основной функции. Эта структура будет предпочтительнее глобальной struct A. Следующая строка определяет переменную типа a типа struct A. Поскольку a struct A был объявлен в области основной функции, то там, где компилятор будет искать это определение там. Он не находит его (он прокомментировал). Первый пример компилируется, потому что есть определение в той же области. Следующий пример будет скомпилирован, поскольку он указал, что a находится в глобальном пространстве имен:

struct A{ int i = 10; };

int main() {
//    struct A{ int i = 20; };
    struct A;
    struct ::A a;
}

Ответ 3

Он не компилируется, потому что он не может найти определение для A.

int main() {
//    struct A{ int i = 20; };
      struct A;
      struct A a;
}

Приведенный выше код равен вашему первому примеру, поскольку глобальный A затенен локальным A. Во втором примере A не имеет определения. Это просто прототип. Предполагается, что прототипы помещаются перед фрагментом кода, которому требуется определение, когда определение помещается ПОСЛЕ кода, который ему нужен. Если компилятор не может найти это определение, он потерпит неудачу, потому что он не знает, что такое A (глобальное определение затенено локальным прототипом, что приводит к его игнорированию).