Чому я не можу ініціалізувати static
членів даних у класі?
Стандарт C ++ дозволяє ініціалізувати лише статичні постійні типи інтегралів чи перерахування всередині класу. Це причина a
, яку дозволено ініціалізувати, а інші - ні.
Довідка:
C ++ 03 9.4.2 Статичні члени даних
§4
Якщо статичний член даних має інтегральний характер const або тип перерахування const, його декларація у визначенні класу може визначати константу-ініціалізатор, який повинен бути інтегральним постійним виразом (5.19). У цьому випадку член може з'являтися в цілісних постійних виразах. Член все ж повинен бути визначений в області простору імен, якщо він використовується в програмі, а визначення сфери простору імен не повинно містити ініціалізатор.
Що таке цілісні типи?
C ++ 03 3.9.1 Основні типи
§7
Типи bool, char, wchar_t, а також підписані та непідписані цілі цілі типи називаються інтегральними типами.43) Синонім цілісного типу - це цілочисельний тип.
Виноска:
43) Тому перерахування (7.2) не є цілісними; однак перерахування можуть бути підвищені до int, unsigned int, long або unsigned long, як зазначено в 4.5.
Обхід:
Ви можете використовувати фокус enum, щоб ініціалізувати масив усередині свого класу.
class A
{
static const int a = 3;
enum { arrsize = 2 };
static const int c[arrsize] = { 1, 2 };
};
Чому Стандарт не дозволяє цього?
Б'ярне пояснює це влучно тут :
Клас, як правило, оголошується у файлі заголовка, а файл заголовка, як правило, включається у багато одиниць перекладу. Однак, щоб уникнути складних правил лінкера, C ++ вимагає, щоб кожен об'єкт мав унікальне визначення. Це правило було б порушено, якби C ++ дозволив визначити об'єкти, які потрібно зберігати в пам'яті як об'єкти, в класі.
Чому static const
дозволені лише цілісні типи та перерахунки в ініціалізації в класі?
Відповідь прихована в цитаті Бярна, читайте її уважно:
"C ++ вимагає, щоб кожен об'єкт мав унікальне визначення. Це правило було б порушено, якщо C ++ дозволило визначити в класі об'єкти, які потрібно зберігати в пам'яті як об'єкти".
Зауважте, що лише static const
цілі числа можуть розглядатися як постійні часу компіляції. Компілятор знає, що ціле значення не зміниться в будь-який час, і отже, він може застосувати власну магію та застосувати оптимізацію, компілятор просто накреслює таких членів класу, тобто вони більше не зберігаються в пам'яті, оскільки необхідність зберігання в пам'яті видаляється , це дає такі змінні виняток із правила, згаданого Б'ярном.
Тут варто звернути увагу, що навіть якщо static const
інтегральні значення можуть мати ініціалізацію в класі, то адресація таких змінних заборонена. Можна взяти адресу статичного члена, якщо (і лише якщо) він має позакласне визначення. Це додатково підтверджує міркування вище.
перерахунки це дозволено, оскільки значення переліченого типу можна використовувати там, де очікуються вставки. див. цитування вище
Як це змінюється на C ++ 11?
C ++ 11 певною мірою послаблює обмеження.
C ++ 11 9.4.2 Статичні члени даних
§3
Якщо статичний член даних має const буквальний тип, його декларація у визначенні класу може визначати дужку або рівний ініціалізатор, у якому кожен ініціалізатор-застереження, яке є виразним призначенням, є постійним виразом. Статичний член даних буквального типу може бути оголошений у визначенні класу, constexpr specifier;
якщо так, його декларація повинна вказувати дужку або рівний ініціалізатор, в якому кожен ініціалізатор-застереження, яке є призначенням-виразомє постійним виразом. [Примітка. В обох цих випадках член може відображатися в постійних виразах. —Закінчити примітку] Член все одно повинен бути визначений в області простору імен, якщо він використовується в програмі, а визначення області простору імен не повинно містити ініціалізатор.
Крім того , C ++ 11 буде дозволяти (§12.6.2.8) нестатичних член даних повинні бути ініційовані , де вона оголошена (в своєму класі). Це буде означати дуже просту семантику користувачів.
Зауважте, що ці функції ще не були впроваджені в останній gcc 4.7, тому ви все одно можете отримати помилки компіляції.