Рассмотрим следующее:
struct X {
X() {}
X(X&&) { puts("move"); }
};
X x = X();
В С++ 14 переход может быть отменен, несмотря на то, что конструктор перемещения имеет побочные эффекты благодаря [class.copy]/31,
Это разрешение операций копирования/перемещения... разрешено в следующих случаях... когда временный объект класса, который не был привязан к ссылке (12.2), будет скопирован/перемещен к объекту класса с тем же самым cv-неквалифицированным типом
В С++ 17 эта пуля была удалена. Вместо этого движение, как гарантируется, будет отменено благодаря [dcl.init]/17.6.1:
Если выражение инициализатора является значением prvalue, а cv-unqualified версия типа источника - то же самое класс как класс адресата, выражение инициализатора используется для инициализации адресата объект. [Пример:
T x = T(T(T()));
вызывает конструктор по умолчаниюT
для инициализацииx
. - конец пример]
До сих пор факты, о которых я говорил, хорошо известны. Но теперь измените код так, чтобы он читал:
X x({});
В С++ 14 выполняется разрешение перегрузки, а {}
преобразуется во временный тип x
с использованием конструктора по умолчанию, а затем перемещается в x
. Правила исключения копий позволяют исключить этот шаг.
В С++ 17 разрешение перегрузки одинаков, но теперь [dcl.init]/17.6.1 не применяется, и пуля с С++ 14 больше не существует. Не существует выражения инициализатора, так как инициализатор представляет собой список бит-init. Вместо этого оказывается, что применяется [dcl.init]/(17.6.2):
В противном случае, если инициализация является прямой инициализацией или если она является копией-инициализацией, где cv-неквалифицированная версия типа источника - это тот же класс, что и производный класс класса назначения, конструкторы. Соответствующие конструкторы перечислены (16.3.1.3), и лучший выбирается с помощью разрешения перегрузки (16.3). Выбранный таким образом конструктор называется для инициализации объекта с выражением инициализатора или списком выражений в качестве аргумента (ов). Если нет конструктор, или разрешение перегрузки неоднозначно, инициализация плохо сформирована.
Кажется, что требуется вызвать конструктор перемещения, и если в каком-либо другом стандарте есть правило, в котором говорится, что это нормально, я не знаю, где он находится.