2015-04-23 2 views
17

GCC (протестировано с 4.9) принимает следующий TestCase:перегрузки между НКУ и лязгом с участием перемещения конструктора и 'Производная (Base &&)' конструктор

struct Base {}; 

struct Derived : Base { 
    Derived(); 
    explicit Derived(const Derived&); 
    explicit Derived(Derived&&); 
    explicit Derived(const Base&); 
    Derived(Base&&); 
}; 

Derived foo() { 
    Derived result; 
    return result; 
} 

int main() { 
    Derived result = foo(); 
} 

Clang (проверено с 3.5) отклонит его следующим сообщение об ошибке:

test.cpp:13:10: error: no matching constructor for initialization of 'Derived' 
    return result; 
     ^~~~~~ 
test.cpp:8:5: note: candidate constructor not viable: no known conversion from 'Derived' to 'Base &&' for 1st argument 
    Derived(Base&&); 
    ^
test.cpp:4:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided 
    Derived(); 
    ^

Кто такой?

ответ

14

Я верю, что 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 определяет преобразование из типов его параметров с типом его класс. Такой конструктор называется преобразование конструктор.

+0

Но он говорит: «Если тип, если первый параметр не является ссылкой rvalue, он выполняется снова». Так как это так, разрешение перегрузки не выполняется снова. – Columbo

+0

@Columbo: Он говорит: «Если тип первого параметра не является ссылкой rvalue ** к типу объекта **», разрешение перегрузки выполняется снова. Здесь это ссылка rvalue, но не тип объекта. (Обратите внимание, что здесь «объект» означает «копируемый объект» с начала абзаца, который является объектом типа 'Derived'.) – HighCommander4

+0

Ahh, правильно, правильно. – Columbo

 Смежные вопросы

  • Нет связанных вопросов^_^