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

Действительно ли мне нужно реализовать созданный пользователем конструктор для объектов const?

У меня есть код:

class A {
  public:
    A() = default;

  private:
    int i = 1;
};

int main() {
  const A a;
  return 0;
}

Он компилируется отлично на g++ (см. ideone), но с ошибкой: clang++ с ошибкой:

инициализация по умолчанию объекта const типа 'const A' требует созданного пользователем конструктора по умолчанию

Я сообщил об этой проблеме в LLVM bug-tracker и получил ее INVALID.

Я вижу совершенно бессмысленно пытаться убедить разработчиков clang. С другой стороны, я не вижу причины такого ограничения.


Может ли кто-нибудь посоветовать, если С++ 11 Standard так или иначе подразумевает, что этот код недействителен? Или я должен просто сообщить об ошибке g++? Или, может быть, существует достаточная свобода в языковых правилах для обработки этого кода во многих отношениях?

4b9b3361

Ответ 1

N3797 §8.5/7 гласит:

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

Нет никакого другого примера или объяснения этого. Я согласен, что это выглядит довольно странно. Кроме того, правило было обновлено на С++ 11, чтобы быть более ограничительным, чем в С++ 03, когда типы классов нуждались в конструкторах, объявленных пользователем. (Ваш конструктор объявляется пользователем.)

Обходным путем является запрос инициализации значения с помощью {} или использование определения Dietmar умного вне класса inline.

GCC предоставляет диагноз (и довольно хороший, ссылаясь на более новые требования к С++ 11), если вы добавляете другой элемент без инициализатора.

  private:
    int i = 1;
    int j;

unmem.cpp:11:11: error: uninitialized const ‘a’ [-fpermissive]
   const A a;
           ^
unmem.cpp:1:7: note: ‘const class A’ has no user-provided default constructor
 class A {
       ^
unmem.cpp:3:5: note: constructor is not user-provided because it is explicitly defaulted in the class body
     A() = default;
     ^
unmem.cpp:7:9: note: and the implicitly-defined constructor does not initialize ‘int A::j’
     int j;

Источник GCC относится к DR 253, почему должны быть инициализированы пустые или полностью инициализированные объекты const? Это открытая проблема в стандарте, последняя обновленная в августе 2011 года (post-С++ 11) с этой заметкой:

Если неявный конструктор по умолчанию инициализирует все подобъекты, не требуется инициализатор.

Поэтому, если Clang соответствует С++ 11 (и будет соответствовать требованиям С++ 14), GCC внедряет последнее мышление комитета по стандартизации.

Подана ошибка GCC. Я предсказываю, что вам понадобится -pedantic, чтобы получить диагноз, когда (и если) ошибка исправлена.

Ответ 2

Обратите внимание, что вы можете легко превратить свой класс в тот, у которого есть пользовательский конструктор по умолчанию:

class A {
  public:
    A();

  private:
    int i = 1;
};

inline A::A() = default;

В соответствии с пунктом 8.4.2 [dcl.fct.def.default], пункт 4:

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

Это подразумевает, что функция, которая явно не дефолтна по первому объявлению, не предоставляется пользователям. В сочетании с 8,5 [dcl.init] абзацем 6

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

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

Ответ 3

Изменить: Ниже приведена устаревшая информация. Я только что прошел через N3797, и вот что я нашел:

§ 8.5/7 [dcl.init]
Если программа вызывает инициализацию по умолчанию объекта const-квалифицированного типа T, T должен быть типом класса с a пользовательский конструктор по умолчанию.

Обратите внимание на стандартную цитату в приведенной ниже ссылке: объявленный пользователем.


Следующая программа компилируется в g++, но не clang++:

struct A {};

void f()
{
  A const a;
}

И это может быть связано с этим отчет об ошибке, где он был "исправлен". g++ не может скомпилировать его, если он содержит данные, если они не инициализированы. Обратите внимание, что int member = 1 больше не сделает A POD. Сравнительно, clang++ отвергает все перестановки (пустые классы и члены данных инициализированы или нет). Для интерпретации того, что стандарт означает в следующем абзаце:

§ 8.5/9 [dcl.init] говорит:

Если для объекта не задан инициализатор, а объект имеет значение (возможно, cv-qualified) тип класса не-POD (или его массив), объект должен быть инициализирован по умолчанию; если объект имеет const-qual type, тип базового класса должен иметь объявленный пользователем конструктор по умолчанию. В противном случае, если инициализатор не установлен заданный для объекта, объект и его подобъекты, если они есть, имеют неопределенное начальное значение; если объект или любой из его подобъектов имеют const-квалифицированный тип, программа плохо сформирована.

См. Почему С++ требует, чтобы пользовательский конструктор по умолчанию устанавливал по умолчанию объект const?. Предположительно программа плохо сформирована if the object is of const-qualified POD type, and there is no initializer specified (because POD are not default initialized). Обратите внимание, как g++ ведет себя следующим образом:

struct A {int a;};
struct B {int a = 1;};
int main() 
{
    A a;
    B b;
    const A c; // A is POD, error
    const B d; // B is not POD, contains data member initializer, no error
}