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

Вызывается конструктор перемещения после вызова функции преобразования?

Рассмотрим следующий пример:

struct T { };

struct S {
    operator T();
};

S s;
T t = s;

[dcl.init] приведет нас к [over.match.copy], который найдет функцию преобразования operator T(). Но мы сделали это в этот момент или нам нужно вызвать T(T&& rhs), привязывая rhs к возврату operator T() через [dcl.init.ref]? Существуют ли какие-либо различия в ответе на этот вопрос между С++ 11 и С++ 1z?

4b9b3361

Ответ 1

Это подпадает под [dcl.init]/17.6.3, что довольно ясно о том, что происходит после разрешения перегрузки, выбирает функцию преобразования

Выбранная функция вызывается с выражением инициализатора как ее аргумент; если функция является конструктором, вызов является prvalue cv-неквалифицированная версия типа назначения, конечный объект инициализируется конструктором. Вызов используется для direct-initialize, согласно вышеприведенным правилам, объект, который назначение инициализации копирования.

В вашем случае это, в свою очередь, пересчитывается в [dcl.init]/17.6.1:

Если выражение инициализатора является prvalue и cv-unqualified версия типа источника - это тот же класс, что и класс destination, выражение инициализатора используется для инициализации объект назначения.


В С++ 11 второй шаг вызывает конструктор перемещения, поскольку он не имеет пули, соответствующей С++ 17 17.6.1. Вместо вы снова танцуете разрешение с прямой инициализацией/перегрузкой:

Если инициализация является прямой инициализацией, [...], конструкторы считается. Соответствующие конструкторы перечислены ([over.match.ctor]), а лучший выбирается через разрешение перегрузки ([over.match]). Выбранный таким образом конструктор вызванный для инициализации объекта, с выражением инициализатора или выражение-список как его аргумент (ы). Если конструктор не применяется, или разрешение перегрузки неоднозначно, инициализация плохо сформирована.

Этот шаг может (и на практике будет) устранен; см. [class.copy]/31.


Более интересный случай на самом деле

T t(s);

который в соответствии с формулировкой С++ 17 на самом деле требуется для вызова конструктора перемещения, поскольку он использует правило прямой инициализации и имеет разрешение перегрузки на конструкторах T. Это выбирает конструктор перемещения T и вызывает его для инициализации T, преобразуя s в значение T, которое материализуется во временное и привязывается к параметру конструктора перемещения. Пуля 17.6.1 просто недоступна в процессе, а пуля в С++ 11 [class.copy]/31 (теперь [class.copy.elision]/1), которые разрешили исключение в этом сценарии, были удалены в С++ 17.

Это скорее всего дефект.