Почему C ++ запрещает анонимные структуры?

93

Некоторые компиляторы C ++ допускают анонимные объединения и структуры как расширение стандартного C ++. Это немного синтаксического сахара, которое иногда бывает очень полезно.

Какое объяснение препятствует тому, чтобы это стало частью стандарта? Есть технические препятствия? Философский? Или просто недостаточно, чтобы это оправдать?

Вот пример того, о чем я говорю:

struct vector3 {
  union {
    struct {
      float x;
      float y;
      float z;
    };
    float v[3];
  };
};

Мой компилятор примет это, но предупреждает, что «безымянная структура / объединение» является нестандартным расширением C ++ .

Адриан Маккарти
источник
3
Очевидно, есть некоторая путаница в том, что вы имеете в виду. Не могли бы вы привести пример кода, который компилируется только благодаря расширению компилятора?
Роб Кеннеди,
75
Обратите внимание, что есть две концепции, которые звучат похоже, но сильно отличаются: безымянные структуры и анонимные структуры . Первый - это тот, который поддерживает C ++: struct { int i; } a; a.i = 0;(у типа нет имени). Второй - это тот, который C ++ не поддерживает: struct { int i; }; i = 0;(у типа нет имени, и он ускользает в окружающую область видимости). C ++, однако, делает поддержку как безымянные и анонимные объединения .
Йоханнес Шауб - лит,
Это похоже на довольно интересную векторную библиотеку VMMLib. Я считаю, что проблема в том, что объединение содержит безымянную структуру, но я не уверен.
greyfade
1
FWIW Это «anonmyous», а не «безымянный», и профсоюзы будут поддерживаться как говорит LITB. stackoverflow.com/q/14248044/560648
Гонки легкости на орбите
1
@AdrianMcCarthy: Это нормально (FSVO «отлично»; надоедливый компилятор загадочен), но именно «безымянный» - это несвязанная стандартная концепция.
Гонки легкости на орбите

Ответы:

50

Как отмечали другие, анонимные объединения разрешены в стандартном С ++, но анонимные структуры - нет.

Причина этого в том, что C поддерживает анонимные объединения, но не анонимные структуры *, поэтому C ++ поддерживает первое для совместимости, но не второе, поскольку оно не требуется для совместимости.

Кроме того, в C ++ нет особого смысла использовать анонимные структуры. Использование вы демонстрируете, чтобы иметь структуру , содержащую три поплавков , которые могут быть переданы либо .v[i], или .x, .yи .z, я считаю , результаты в непредсказуемом поведении в C ++. C ++ не позволяет вам писать, скажем .v[1], одному члену союза , а затем читать , скажем , из другого члена .y. Хотя код, который делает это, не редкость, на самом деле он не очень хорошо определен.

Возможности C ++ для пользовательских типов предоставляют альтернативные решения. Например:

struct vector3 {
  float v[3];
  float &operator[] (int i) { return v[i]; }
  float &x() { return v[0]; }
  float &y() { return v[1]; }
  float &z() { return v[2]; }
};

* C11 явно добавляет анонимные структуры, поэтому будущая версия C ++ может добавить их.

bames53
источник
2
+1: мой пример основан на неопределенном поведении в C ++ - о чем я не знал, когда писал вопрос.
Адриан Маккарти
2
«C ++ не позволяет вам писать в один член объединения [...], а затем читать из другого члена» - если только указанные элементы не являются объектами стандартного макета и разделяют общую начальную последовательность собственных членов, а вы » повторно записывают / читают свои члены в указанной общей начальной последовательности. Это будет разрешено (т.е. определено).
underscore_d
5
@underscore_d: Да, если типы имеют стандартный макет с общей начальной последовательностью. Однако структура никогда не может быть псевдонимом с массивом таким образом, потому что правила «общей начальной последовательности» C ++ гласят, что общая начальная последовательность может быть только между структурами . Массивы не упоминаются, поэтому они не могут быть такими псевдонимами.
Никол Болас
@NicolBolas О, ха-ха - поверьте мне - я много раз хотел, чтобы в это пособие были включены массивы и другие примитивы! Но я не особо задумывался о возможных практических ограничениях этого, так что, вероятно, это не так просто, как кажется сейчас. Мой комментарий был более общим, но, возможно, я рискнул намекнуть из-за упущения, что я думал, что массивы были включены в это, так что спасибо за добавление этого.
underscore_d
«Причина в том, что C поддерживает анонимные объединения, но не анонимные структуры» - Нет. В вашей сноске поясняется, что вы говорили здесь о C99 или ранее. Термин «анонимный союз» нигде в стандарте C99 не встречается. GCC утверждает в диагностике (с параметрами -std = c99 -pedantic), что «ISO C99 не поддерживает безымянные структуры / объединения». В стандарте ничего не упоминается о безымянных членах, кроме неназванных битовых полей. Я не совсем уверен, являются ли объявления структур объявлениями, но если это так, анонимные объединения являются нарушением ограничения для 6.7p2, в лучшем случае undefined.
21

Я скажу, вы можете очистить свое vector3объявление, просто используяunion

union vector3 {
  struct { float x, y, z; } ;
  float v[3] ;
} ;

Конечно, анонимные структуры были расширением MSVC . Но ISO C11 допускает это сейчас, и gcc позволяет это , как и компилятор Apple llvm.

Почему в C11, а не в C ++ 11? Я не уверен, но практически говоря, большинство компиляторов C ++ (gcc ++, MSVC ++ и Apple C ++) их поддерживают.

бобобобо
источник
1
+1 за обновленную информацию. Причина, по которой у меня была внешняя структура, заключалась в том, что «настоящий код» также имел методы.
Адриан МакКарти,
Единственное, что вы не можете делать с объединением, - это иметь статические элементы данных или использовать наследование .
bobobobo
2
Спасибо. Я никогда не знал, что объединение можно использовать как структуру или класс.
Адриан Маккарти
Я знаю, что студия Sun по умолчанию не поддерживала анонимные структуры до C ++ 11. Если вы пишете кросс-платформенный код, а компиляторы не обновлены до C + 11, не используйте анонимную структуру.
irsis
6

Не уверен, что вы имеете в виду. Раздел 9.5 спецификации C ++, пункт 2:

Союз формы

union { member-specification } ;

называется анонимным союзом; он определяет безымянный объект безымянного типа.

Вы тоже можете делать такие вещи:

void foo()
{
  typedef
  struct { // unnamed, is that what you mean by anonymous?
    int a;
    char b;
  } MyStructType; // this is more of a "C" style, but valid C++ nonetheless

  struct { // an anonymous struct, not even typedef'd
    double x;
    double y;
  } point = { 1.0, 3.4 };
}

Не всегда очень полезно ... хотя иногда полезно в неприятных определениях макросов.

Дэн
источник
11
-1, потому что он говорит, что он определяет анонимную структуру. См. Комментарии выше к вопросу - вы определяете безымянную структуру, а не анонимную.
Йоханнес Шауб - лит
1

Союзы могут быть анонимными; см. Стандарт, 9.5 параграф 2.

Какую цель, по вашему мнению, выполняет анонимная структура или класс? Прежде чем размышлять, почему чего-то нет в Стандарте, я хотел бы иметь некоторое представление, почему это должно быть, и я не вижу использования анонимной структуры.

Дэвид Торнли
источник
1

Основываясь на правке, комментариях и этой статье MSDN: Анонимные структуры , я рискну предположить - она ​​плохо согласуется с концепцией инкапсуляции. Я бы не ожидал, что член класса будет возиться с пространством имен моего класса, кроме простого добавления одного члена. Более того, изменения анонимной структуры могут повлиять на мой класс без разрешения.

JonM
источник
1
Из-за того, как создаются анонимные структуры / союзы (это особый встроенный синтаксис, который нельзя скрыть, кроме макроса), вас не удивит, что какой-то член, который вы используете, является анонимным. Поэтому я не думаю, что это рассуждение имеет смысл. Реальная причина заключается в том , что анонимные союзы имеют поддержку в C ++, для совместимости C только. C не поддерживает анонимные структуры (до C11), поэтому C ++ не поддерживает.
bames53 08
1

Ваш код

union {
  struct {
    float x;
    float y;
    float z;
  };
  float v[3];
};

как

union Foo {
   int;
   float v[3];
};

что, безусловно, недействительно (в C99 и ранее).

Причина, вероятно, в том, чтобы упростить синтаксический анализ (в C), потому что в этом случае вам нужно только проверить, что тело структуры / объединения имеет только «операторы декларатора», такие как

Type field;

Тем не менее, gcc и "другие компиляторы" поддерживают безымянные поля в качестве расширения.

Изменить: анонимные структуры теперь официально поддерживаются в C11 (§6.7.2.1 / 13).

Kennytm
источник
5
С точки зрения синтаксического анализа я не думаю, что union { ... }это отличается от struct { ... }. Первое верно, второе - нет.
Йоханнес Шауб - лит,
3
Учитывая, насколько абсурдно трудным для синтаксического анализа C ++ в целом, я сомневаюсь, что стандартное обязательство запрещает безымянные структуры и объединения только для упрощения синтаксического анализа.
Адриан Маккарти,
@ Адриан: Я сказал C, а не C ++. C ++ принимает синтаксис C и расширяет его. Вероятно, создатели C ++ не видят необходимости разрешать безымянные члены структуры / объединения, чтобы не вмешиваться в эту часть синтаксиса.
kennytm
@ Адриан, хороший момент, Адриан, я всегда не думал, что «слишком сложно реализовать» когда-либо будет проблемой для
Бьярна
И C, и C ++ поддерживают безымянные объединения, поэтому union { ... };недопустимый комментарий неверен.
bames53 08