Я верю, что Clang здесь. GCC не должен принимать код.
Причиной является разрешение способ перегрузки конструкторами для объекта копии происходящих в return
заявлении указывается в [class.copy] p32
(курсив мой):
Когда критерии элизии конструктора копирования/перемещения выполнены , [...], а подлежащий копированию объект обозначается lvalue, [...], . Разрешение перегрузки для выбора конструктора для копии сначала выполняется так, как если бы объект был обозначен rvalue. Если первый разрешение перегрузки не может или не было выполнено, или если тип первого параметра выбранного конструктора не является Rvalue ссылки на тип объекта (возможно, CV-квалифицированный), перегружать разрешение выполняется снова , рассматривая объект как lvalue.
В этом примере, критерий элизий выполнены (по первой пуле в [class.copy] p31
) и объект, подлежащий копированию, обозначен-значение, поэтому применяется в этом пункте.
Разрешение первой попытки, как если бы объект был назначен значением rvalue. Конструкторы explicit
не являются кандидатами (см. Ниже объяснение причины), поэтому выбран конструктор Derived(Base&&)
. Однако это подпадает под «тип первого параметра выбранного конструктора не является ссылкой rvalue на тип объекта» (вместо этого это ссылка rvalue на тип базового класса объекта), поэтому разрешение перегрузки должно быть выполнено снова , рассматривая объект как lvalue.
Это второе разрешение перегрузки выходит из строя, поскольку единственный жизнеспособный конструктор (опять же, конструкторы explicit
не являются кандидатами) имеет параметр ссылки rvalue, который не может привязываться к lvalue. Clang показывает полученную ошибку с ошибкой разрешения перегрузки.
Чтобы завершить объяснение, вот почему explicit
Конструкторы не являются кандидатами либо разрешения перегрузки (все выделено мной).
Во-первых, [dcl.init] p15
говорит, что:
инициализации, которая происходит в = форме распорки или равно-инициализатора или условие (6.4), а также в аргумента передача, функция возвращает, генерируя исключение (15.1), обрабатывая исключение (15.3) и инициализацию элемента агрегата (8.5.. 1), является называется копирования инициализации»
Далее мы рассмотрим [over.match.ctor] p1
:
Для копирования инициализации, функции-кандидаты все преобразования конструкторы (12.3.1) этого класса.
Наконец, мы видим, что explicit
конструкторов не преобразование конструкторов в [class.conv.ctor] p1
:
Конструктор объявлен без функции спецификатора explicit
определяет преобразование из типов его параметров с типом его класс. Такой конструктор называется преобразование конструктор.
Но он говорит: «Если тип, если первый параметр не является ссылкой rvalue, он выполняется снова». Так как это так, разрешение перегрузки не выполняется снова. – Columbo
@Columbo: Он говорит: «Если тип первого параметра не является ссылкой rvalue ** к типу объекта **», разрешение перегрузки выполняется снова. Здесь это ссылка rvalue, но не тип объекта. (Обратите внимание, что здесь «объект» означает «копируемый объект» с начала абзаца, который является объектом типа 'Derived'.) – HighCommander4
Ahh, правильно, правильно. – Columbo