Чому C ++ забороняє анонімні структури?


92

Деякі компілятори C ++ дозволяють анонімні об'єднання та структури як розширення до стандартного C ++. Це трохи синтаксичного цукру, що іноді дуже корисно.

Яке обґрунтування перешкоджає цьому бути частиною стандарту? Чи існує технічна перешкода? Філософський? Або просто недостатньо потреби, щоб це виправдати?

Ось зразок того, про що я говорю:

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

Мій компілятор прийме це, але попереджає, що "безіменний struct / union" - це нестандартне розширення для C ++ .


3
Очевидно, є певна плутанина щодо того, що ви маєте на увазі. Не могли б ви навести приклад коду, який компілюється лише через розширення компілятора?
Роб Кеннеді,

73
Зверніть увагу, що є дві концепції, які звучать схоже, але значно відрізняються: неназвані структури та анонімні структури . Перший - це той, який підтримує C ++: struct { int i; } a; a.i = 0;(тип не має імені). Другий - це той, який C ++ не підтримує: struct { int i; }; i = 0;(тип не має імені, і він переходить у навколишню область). C ++, проте, робить підтримку як безіменні і анонімні об'єднання .
Йоханнес Шауб - літ

Це виглядає як досить цікава векторна бібліотека VMMLib. Я вважаю, що проблема полягає в тому, що союз містить неназвану структуру, але я не впевнений.
greyfade

1
FWIW Це "неприємно", а не "без імені", і профспілки є підтримуватися як каже LITB. stackoverflow.com/q/14248044/560648
Гонки легкості на орбіті

1
@AdrianMcCarthy: Це чудово (FSVO "чудовий"; надокучливий компілятор загадковий), але саме "неназваний" - це не пов'язане, стандартне поняття.
Гонки легкості на орбіті

Відповіді:


50

Як зазначали інші, анонімні спілки дозволені в стандартній C ++, але анонімні структури - ні.

Причиною цього є те, що C підтримує анонімні об'єднання, але не анонімні структури *, тому C ++ підтримує перший для сумісності, але не другий, оскільки він не потрібний для сумісності.

Більше того, анонімні структури в C ++ не надто корисні. Використання ви демонструєте, щоб мати структуру , яка містить три поплавців , які можуть бути передані або .v[i], або .x, .yі .z, я вважаю , результати в непередбаченому поводженні в C ++. С ++ не дозволяє писати одному члену спілки, скажімо .v[1], а потім читати від іншого члена, скажімо .y. Хоча код, який робить це, не рідкість, він насправді не є чітко визначеним.

Засоби С ++ для визначених користувачем типів пропонують альтернативні рішення. Наприклад:

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 ++ може додавати їх.


2
+1: Мій приклад спирається на невизначену поведінку в C ++ - те, про що я не знав ще, коли писав запитання.
Адріан Маккарті

2
"C ++ не дозволяє писати одному члену об'єднання [...], а потім читати від іншого члена" - якщо зазначені члени не є об'єктами стандартного макету і не мають спільної початкової послідовності власних членів, і ви ' переписування / читання своїх членів у межах зазначеної загальної початкової послідовності. Це буде дозволено (тобто визначено).
underscore_d

5
@underscore_d: Так, якщо типи є стандартним макетом із загальною початковою послідовністю. Однак структура ніколи не може псевдонімом масиву таким чином, оскільки правила "загальної початкової послідовності" на C ++ визначають, що загальна початкова послідовність може бути лише між структурами . Масиви не згадуються, тому вони не можуть псевдонімами, подібними до цього.
Nicol Bolas,

@NicolBolas О, ха-ха - повірте мені - я вже багато разів бажав, щоб масиви та інші примітиви були включені в цю допомогу! Але я не надто замислювався над можливими практичними обмеженнями щодо цього, тому, ймовірно, це не так просто, як здається зараз. Мій коментар був більш загальним, але, можливо, ризикував натякнути на упущення, що я думав, що до цього включені масиви, тож дякую за додавання цього.
underscore_d

"Причиною цього є те, що C підтримує анонімні спілки, але не анонімні структури" - Ні. У вашій виносці пояснюється, що ви тут говорили про C99 або раніше. Термін "анонімний союз" ніде не зустрічається в стандарті C99. GCC стверджує в діагностиці (із параметрами -std = c99 -педант), що "ISO C99 не підтримує неназвані структури / об'єднання". Стандарт не згадує нічого про неназваних членів, крім неназваних бітових полів. Я не зовсім впевнений, чи є структурні декларації деклараціями, але якщо вони є, анонімні спілки є порушенням обмежень відповідно до 6.7p2, в кращому випадку невизначеним.

21

Скажу, ви можете очистити свою vector3декларацію, просто використовуючиunion

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

Звичайно, анонімні структури були розширенням MSVC . Але ISO C11 дозволяє це зараз, а gcc це дозволяє , а також компілятор llvm від Apple.

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


1
+1 для оновленої інформації. Причиною того, що у мене була зовнішня структура, було те, що "реальний код" також мав методи.
Адріан Маккарті

Єдине, що ви не можете зробити з об’єднанням, - це статичні члени даних або використовувати спадщину .
bobobobo

2
Дякую. Я ніколи новий союз не міг використовувати як структуру чи клас.
Адріан Маккарті,

Я знаю, що Sun studio за замовчуванням не підтримував анонімну структуру до C ++ 11. Якщо ви пишете крос-платформний код, а компілятори не оновлені до C + 11, тоді не використовуйте анонімну структуру.
ірсіс

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 пункту 9.5.

Яку мету, на вашу думку, виконує анонімна структура чи клас? Перш ніж роздумувати, чому чогось немає в Стандарті, я хотів би трохи уявити, чому це повинно бути, і я не бачу використання анонімної структури.


1

На основі редагування, коментарів та цієї статті MSDN: Анонімні структури , я ризикую здогадуватися - це погано відповідає концепції інкапсуляції. Я б не очікував, що член класу возиться з моїм простором імен класів, окрім простого додавання одного члена. Крім того, зміни в анонімній структурі можуть вплинути на мій клас без дозволу.


1
Через те, як створюються анонімні структури / об'єднання (це особливий, вбудований синтаксис, який неможливо приховати, крім макросу), ви не можете бути здивовані тим, що якийсь користувач, який ви використовуєте, є анонімним членом. Тому я не думаю, що ці міркування мають якийсь сенс. Реальна причина полягає в тому , що анонімні союзи мають підтримку в C ++, для сумісності C тільки. C не підтримує анонімні структури (до C11), тому C ++ теж не підтримує.
bames53

1

Ваш код

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

це як

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

що, безумовно, є недійсним (у C99 і раніше).

Причиною є, мабуть, спрощення синтаксичного аналізу (на С), оскільки в такому випадку потрібно лише перевірити, чи тіло struct / union має лише "оператори декларатора", як

Type field;

Тим не менш, gcc та "інші компілятори" підтримують неназвані поля як розширення.

Редагувати: анонімні структури тепер офіційно підтримуються в C11 (§6.7.2.1 / 13).


5
З точки зору розбору, я не думаю, що union { ... }це нічим іншим, ніж struct { ... }. Перше дійсне, а друге - ні.
Йоханнес Шауб - літ

3
Беручи до уваги, наскільки абсурдно важко аналізувати C ++ в цілому, я сумніваюся, що стандартні фіксовані заборонені неназвані структури та об'єднання лише для спрощення аналізу.
Адріан Маккарті

@ Адріан: Я сказав C, а не C ++. С ++ приймає синтаксис С та розширює його. Ймовірно, творці C ++ не бачать необхідності дозволяти неназваних членів struct / union, щоб вони не возились з цією частиною синтаксису.
kennytm

@Adrian, хороший момент, Адріане, я завжди не думав, що "занадто важко реалізувати" коли-небудь буде турбувати Б'ярне та екіпаж
bobobobo

І C, і C ++ підтримують неназвані спілки, тому union { ... };недійсний коментар є неправильним.
bames53
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.