2014-10-02 4 views
3

В нижеприведенном фрагменте я могу понять (из пункта 3.3.2/6 second bullet point), что имя B в объявлении struct B* p; вводится в глобальное пространство имен как имя класса.Является ли моя интерпретация слова «первая» в п. 3.3.2/6 правильной?

struct A { 
// struct B{}; 
    int B; 
    struct B* p; 
}; 

void f(B&) {} 

int main() 
{ 
    A a; 
    f(*a.p); 
} 

§3.3.2/6:

Точка декларации класса первого объявленного в разработаны типа спецификатор выглядит следующим образом:

  • за декларацию

    ключ классаатрибут-спецификатор-0optидентификатор;

    идентификатор объявляется класс имяв объеме, что содержит объявление, в противном случае

  • для разработан типа-спецификатор формы

    ключ классаидентификатор

    если выработанного типа спецификатор используются в Decl-спецификаторе-след или параметра-декларация-п функции, определенной в области видимости пространства имен, то идентификатор объявлен как класс имя- в в пространстве имен, содержащем объявление; в противном случае, кроме объявления , идентификатор - это , объявленный в наименьшем пространстве имен или блоке, который содержит объявление . [Примечание: Эти правила также применяются в шаблонах. - конец примечания] [Примечания: Другие формы разработаны типа-спецификатор не объявить новое имя, и, следовательно, должны относиться к существующему имени-типа. См. 3.4.4 и 7.1.6.3. - конец примечание]

Однако если раскомментировать определение struct B{}; внутри struct A, что я сказал ранее в отношении введения имени B в глобальное пространство имен, не происходит больше, поскольку код не компилируется.Я считаю, что это имеет не делать со словом первый (курсив мой) выше, так как теперь имя класса B, в декларации struct B* p; больше не его первая декларация в декларативной области. Правильно ли я это сказал?

Предполагая, что моя интерпретация верна, почему это класс-имяB не вводится в глобальное пространство имен в этом случае? Обратите внимание, что вложенный класс struct B{}; будет скрыт внутри A в этом случае, то есть даже если мы изменим объявление функции f на void f(A::B&), код не будет компилироваться.

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

+3

Впрыск в охватывающее пространство имен, безусловно, совместим с C. – avakar

+0

Не могли бы вы изучить это немного больше? –

+0

C не имеет области класса/структуры, поэтому 'struct S {struct X {int y; }; int x; }; struct X my_var = {42}; 'является законным в C (ну, это уродливо - но он фактически компилируется с clang и gcc, хотя и с предупреждением в последнем). – dyp

ответ

2

Вы правы, что первый ключевое слово в §3.3.2/6 является также причиной для следующего:

struct A { 
    struct B *p; 
    struct B{}; 
    int b; 
}; 

void f(B* arg) { 
    std::cout << std::is_same<decltype(arg), A::B*>::value; // not the same type 
} 

int main() 
{ 
    A a; 
    f(a.p); 
} 

почему это, что имя класса B не впрыскивается в глобальном пространстве имен в этом случае?

Как DYP отметил, [basic.lookup.elab]/2 объясняет, что 3.3.2 осуществляется только в случае, если никакой предыдущей декларации не может быть найден

Если выработанный тип -specifier вводится класс ключа и этот поиск не находит имя-типа ранее объявленную, или если разработаны типа спецификатор появляется в объявлении с формой:

класс-ключ атрибута спецификатора -seqopt identifier;

разработан тип спецификатор является свидетельством того, что вводит имя-класса , как описано в 3.3.2.the

Наконец я разыскал это поведение, возможно, наследственная от C99 6.7.2.3/P8

Если тип спецификатор формы

-структуры или Всесоюзный идентификатор

происходит , кроме как часть одного из указанных выше форм, и никакой другой декларации из идентификатор в качестве тега видна, то он объявляет неполное структуры или объединения типа, и объявляет идентификатор в качестве тега , что type.113)

113) аналогичной конструкции с enum не существует.

+0

Очень хороший ответ, но я считаю, что приведенный выше пример @dyp более наглядно иллюстрирует совместимость с C в отношении инъекции класса, предложенной во второй палитре 3.3.2/6 (+1). –

0

Я бы сказал, что ваша интерпретация верна. Когда вы раскомментируете struct B{};, линия struct B* p; будет просто ссылаться на эту структуру A::B.

Чтобы ответить на ваш вопрос, почему, когда вы покидаете struct B {};, в глобальном масштабе вводится имя struct B. Я бы сказал, это потому, что авторы не хотели, чтобы вы (несколько) молча объявляли B членом A без использования спецификация участника для имени B.