Подтвердить что ты не робот

Почему конструктор необходим в структуре const?

У меня есть код, похожий на этот:

class AClass {
public:
  struct AStruct { };

  AClass(){}

private:
  const AStruct m_struct;
};

int main() {
  AClass a;
}

Он выдает эту ошибку компиляции (с Clang LLVM версия 5.1):

error: constructor for 'AClass' must explicitly initialize 
       the const member 'm_struct'

Если я укажу конструктор по умолчанию для С++ 11 для struct AStruct, я получаю ту же ошибку:

  struct AStruct {
    AStruct() = default;
  };

Однако это решается путем написания конструктора с пустым телом:

  struct AStruct {
    AStruct(){}  // fixed
  };

Почему мне нужно указывать пустой конструктор? Разве это не автоматически создается с открытым доступом для структур?

Почему конструктор по умолчанию С++ 11 не решает проблему?

4b9b3361

Ответ 1

Из §8.5 [dcl.init]/7:

Если программа запрашивает инициализацию по умолчанию объекта типа const, T, T должен быть типом класса с предоставленным пользователем конструктором по умолчанию.

Конструктор по умолчанию AClass по умолчанию инициализирует член const (см. ниже), так что член должен иметь предоставленный пользователем конструктор по умолчанию. Использование = default не приводит к предоставленному пользователем конструктору по умолчанию, как показано в §8.4.2 [dcl.fct.def.default]/4:

Функция предоставляется пользователем, если она объявлена ​​пользователем и явно не установлена ​​по умолчанию или удалено в его первом объявлении.


Элемент инициализируется по умолчанию для §12.6.2 [class.base.init]/8:

В конструкторе без делегирования, если данный нестатический элемент данных или базовый класс не обозначен идентификатором mem-initializer (включая случай, когда нет списка mem-initializer, поскольку конструктор не имеет ctor -initializer), и сущность не является виртуальным базовым классом абстрактного класса (10.4), то

- если объект является нестатическим элементом данных, у которого есть инициализатор с привязкой или равенством, объект инициализируется, как указано в 8.5;
- в противном случае, если объект является анонимным объединением или вариантом (9.5), инициализация не выполняется; - , в противном случае объект инициализируется по умолчанию (8.5).

Ответ 2

Украденный из @chris ответ, у нас есть этот параграф: §8.5 [dcl.init]/7:

Если программа запрашивает инициализацию по умолчанию объекта типа const, T, T должен быть типом класса с предоставленным пользователем конструктором по умолчанию.

Затем мы можем построить совершенно смешной случай, иллюстрирующий это ограничение:

struct Foo {};
int main() {
  const Foo f;
}

который не компилируется в clang, как это диктует стандарт. Ваш код просто это, но как переменная-член другого класса/структуры.

Мы можем даже это сделать:

struct Foo {int x = 3;};
int main() {
  const Foo f;
}

где все данные, очевидно, инициализированы. Этот последний пример убеждает меня, что это дефект в стандарте.

Мысль, вероятно, была связана с неинициализацией типов POD и const, но формулировка блокирует код, который не связан. Конструкторы по умолчанию в современных С++ часто более чем достаточно хороши, а форсирование Foo(){} - это плохая форма.