Являются ли "анонимные структуры" стандартными? И действительно, что они?
MSDN считает, что анонимные структуры нестандартны в C++:
Расширение Microsoft C позволяет объявлять структурную переменную в другой структуре, не называя ее имени. Эти вложенные структуры называются анонимными структурами. C++ не допускает анонимных структур.
Вы можете получить доступ к членам анонимной структуры, как если бы они были членами в содержащей структуре.
Мне сказали, что эта функция не обязательно такая же, как просто создание безымянной структуры, но я не вижу различия в терминах стандартной формулировки.
C++ 11 говорит:
[C++11: 9/1]
: [..] Спецификатор класса, глава класса которого опускает имя- класса, определяет безымянный класс.
и обеспечивает полную грамматическую конструкцию для определения типа, в котором отсутствует имя.
В C++03 отсутствует эта явная формулировка, но аналогичным образом указывается, что identifier
в определении типа является необязательным, и делает ссылку на "безымянные классы" в 9.4.2/5
а также 3.5/4
,
- Так что MSDN не так, и все это совершенно стандартно?
- Или есть какая-то тонкость, которую я пропускаю между "безымянными структурами / классами" и той же самой при использовании в качестве членов, которая препятствует тому, чтобы они были покрыты этой функциональностью C++03/C++11?
- Я пропускаю какое-то фундаментальное различие между "безымянной структурой" и "анонимной структурой"? Они похожи на синонимы для меня.
3 ответа
Весь стандартный текст относится к созданию "безымянной структуры":
struct {
int hi;
int bye;
};
Просто хороший дружелюбный тип, без доступного имени.
Стандартным образом его можно создать как член:
struct Foo {
struct {
int hi;
int bye;
} bar;
};
int main()
{
Foo f;
f.bar.hi = 3;
}
Но "анонимная структура" немного отличается - это комбинация "безымянной структуры" и того факта, что вы волшебным образом извлекаете из нее элементы в родительском объекте:
struct Foo {
struct {
int hi;
int bye;
}; // <--- no member name!
};
int main()
{
Foo f;
f.hi = 3;
}
В противоположность интуиции † это не просто создает неназванную структуру, которая вложена Foo
, но также автоматически дает вам своего рода "анонимный член", который делает членов доступными внутри родительского объекта.
Именно эта функциональность является нестандартной. GCC поддерживает его, как и Visual C++. Заголовки Windows API используют эту функцию по умолчанию, но вы можете указать, что она вам не нужна, добавив #define NONAMELESSUNION
перед включением заголовочных файлов Windows.
Сравните со стандартной функциональностью "анонимных союзов", которые делают похожую вещь:
struct Foo {
union {
int hi;
int bye;
}; // <--- no member name!
};
int main()
{
Foo f;
f.hi = 3;
}
† Похоже, что хотя термин "безымянный" относится к самому типу (то есть к "классу" или "структуре"), термин "анонимный" относится вместо этого к фактическому экземпляру (с использованием более старого значения "структуры"). "это ближе к" объекту какого-то struct
у типа "). Вероятно, это корень вашей первоначальной путаницы.
То, что Microsoft называет анонимными структурами, не является стандартным. Безымянная структура - это обычная структура, у которой нет имени. С ним мало что можно сделать, если только вы не определите объект этого типа:
struct {
int i;
double d;
} my_object;
my_object.d = 2.3;
Анонимные союзы являются частью стандарта, и они ведут себя так, как вы ожидаете, прочитав описание Microsoft их анонимных структур:
union {
int i;
double d;
};
d = 2.3;
Стандарт говорит об анонимных союзах: [9.5]/5
Союз формы
union { member-specification } ;
называется анонимным союзом; он определяет безымянный объект безымянного типа. Спецификация члена анонимного объединения должна определять только нестатические члены данных. [Примечание: вложенные типы и функции не могут быть объявлены в анонимном объединении. - примечание] Имена членов анонимного объединения должны отличаться от имен любого другого объекта в области, в которой объявлен анонимный союз. В целях поиска имени после определения анонимного объединения члены анонимного объединения считаются определенными в области, в которой объявлен анонимный союз. [ Пример:
void f() { union { int a; const char* p; }; a = 1; p = "Jennifer"; }
Здесь a и p используются как обычные переменные (не являющиеся членами), но, поскольку они являются членами объединения, они имеют один и тот же адрес. - конец примера]
Анонимные структуры, о которых говорит Microsoft, это функция для unions
но применяется к structs
, Это не просто безымянное определение, важно отметить, что члены анонимного объединения / структуры считаются определенными в области, в которой объявлен анонимный союз / структура.
Насколько я знаю, в Стандарте нет такого поведения для неназванных структур. Обратите внимание, что в приведенном примере вы можете достичь вещей, которые иначе были бы невозможны, таких как совместное использование хранилища для переменных в стеке, в то время как анонимные структуры не вносят ничего нового в таблицу.