До С++ 11 мы могли выполнять только инициализацию класса в статических константных элементах интегрального типа или типа перечисления. Stroustrup обсуждает это в своих часто задаваемых вопросах С++, в следующем примере:
class Y {
const int c3 = 7; // error: not static
static int c4 = 7; // error: not const
static const float c5 = 7; // error: not integral
};
И следующие рассуждения:
Итак, почему эти неудобные ограничения существуют? Класс обычно объявляется в файле заголовка, и заголовочный файл обычно включается во многие единицы перевода. Однако, чтобы избежать сложных правил компоновщика, С++ требует, чтобы каждый объект имел уникальное определение. Это правило будет нарушено, если С++ допускает определение класса в классе, которое должно храниться в памяти как объекты.
Однако С++ 11 ослабляет эти ограничения, позволяя инициализацию нестатических членов в классе (§12.6.2/8):
В конструкторе без делегирования, если данный нестатический элемент данных или базовый класс не обозначен идентификатором mem-initializer (включая случай, когда нет списка mem-initializer, поскольку конструктор не имеет ctor -initializer), и сущность не является виртуальным базовым классом абстрактного класса (10.4), то
- если объект является нестатическим членом данных, у которого есть инициализатор скобок или равным, объект инициализируется, как указано в 8.5;
- в противном случае, если объект является вариантом (9.5), инициализация не выполняется;
- в противном случае объект инициализируется по умолчанию (8.5).
В разделе 9.4.2 также допускается инициализация нестационарных статических элементов в классе, если они помечены спецификатором constexpr
.
Итак, что случилось с причинами ограничений, которые мы имели в С++ 03? Мы просто принимаем "сложные правила компоновщика" или что-то еще изменилось, что упрощает его реализацию?