C ++ Конструкторы по умолчанию в объединении с вариантом члена с нетривиальным конструктором по умолчанию - PullRequest
0 голосов
/ 18 мая 2018

Я недавно прочитал описание конструкторов по умолчанию для объединений: Конструктор по умолчанию

Существует следующее правило:

Blockquote Удален неявно объявленный конструктор по умолчанию: [...] T является объединением по крайней мере с одним вариантным членом с нетривиальным конструктором по умолчанию, и ни один вариантный член T не имеет инициализатора элемента по умолчанию. [...]

ТогдаЯ решил выполнить упражнение и проверить правило.

struct Member {
 public:
  // Member() : mX(0) {}
  virtual int GetX() {
    return mX;
  }
  int mX;
};

union DefaultConstructor {
  int mA;
  Member mMember;
  int GetA();
};

При использовании gcc v5.3.1 (я знаю, что он довольно старый) я получаю ожидаемую ошибку:

> ../src/DefaultConstrcutors.cpp: In function ‘void
> Test_DefaultConstructors()’: ../src/DefaultConstrcutors.cpp:26:22:
> error: use of deleted function
> ‘DefaultConstructor::DefaultConstructor()’    DefaultConstructor foo;
>                       ^ In file included from ../src/DefaultConstrcutors.cpp:19:0:
> ../src/DefaultConstructors.h:155:7: note:
> ‘DefaultConstructor::DefaultConstructor()’ is implicitly deleted
> because the default definition would be ill-formed:  union
> DefaultConstructor {
>        ^ ../src/DefaultConstructors.h:157:10: error: union member ‘DefaultConstructor::mMember’ with non-trivial ‘Member::Member()’   
> Member mMember;
>           ^

OkТаким образом, согласно правилу, если я предоставлю инициализатор элемента по умолчанию для варианта элемента, то он должен скомпилироваться.Поэтому я изменил определение объединения на:

union DefaultConstructor {
      int mA = 0;
      Member mMember;
      int GetA();
    };

И теперь он должен скомпилироваться, но я получил ту же ошибку.

Следующим шагом было предоставление вместо инициализатора по умолчанию для mMember.мА (только один вариантный элемент объединения может иметь инициализатор по умолчанию).

union DefaultConstructor {
      int mA;
      Member mMember{};
      int GetA();
    };

Теперь он компилируется.

Вопрос: почему он не компилировался во втором случае, когда у mA был инициализатор по умолчанию?Согласно упомянутому правилу это должно быть возможно.Какое более похожее правило представлено здесь: Объявление объединения

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

У кого-нибудь есть идеи, почему он не работает?

Greetings, Piotr

1 Ответ

0 голосов
/ 18 мая 2018

cppreference, как правило, хороший источник информации, но здесь компилятор прав.Проект n3337 для C ++ 11 содержит в 9.5 союзов [class.union] ненормативную, но явную заметку, в которой говорится:

Если какой-либо элемент нестатических данных объединения имеет нетривиальный конструктор по умолчанию(12.1), конструктор копирования (12.8), конструктор перемещения (12.8), оператор назначения копирования (12.8), оператор назначения перемещения (12.8) или деструктор (12.4), соответствующая функция-член объединения должна быть предоставлена ​​пользователем илибудет неявно удалено (8.4.3) для объединения.

Нет упоминания о том, что не будет иметь место, если один элемент имеет инициализатор элемента по умолчанию.

То же самоепримечание все еще стоит в проекте n4296 для C ++ 14, поэтому я предполагаю, что оно должно быть таким же в фактическом стандарте C ++.Примечания, конечно, не являются нормативными, но их цель состоит в том, чтобы сделать более четкой интерпретацию стандарта, поэтому я предполагаю, что интерпретация cppreference является неправильной, поскольку она не относится к этой заметке, и что интерпретация gcc является правильной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...