2015-08-02 3 views
5

Я понимаю, что компилятор делает copy-elision в коде ниже, поскольку конструкторы копирования и перемещения не вызываются в так называемом copy-initialization, выполненном в main(). См. live example.Выполняя copy-elision, компилятор не рассматривает конструктор копирования в разрешении перегрузки, когда конструктор перемещения удаляется. Зачем?

#include <iostream> 
struct S { 
    S() = default; 
    S(const S&) { std::cout << "copy ctor" << '\n'; } 
    S(S&&) { std::cout << "move ctor" << '\n'; } 
}; 

int main() { 
    S s = S(); 
} 

Но я не могу понять, почему код не компилируется, когда я удаляю конструктор перемещения, как показано ниже:

#include <iostream> 
struct S { 
    S() = default; 
    S(const S&) { std::cout << "copy ctor" << '\n'; } 
    S(S&&) = delete; 
}; 

int main() { 
    S s = S(); 
} 

Я не могу найти что-либо в §12.8/32 (N4140) что в данном случае может быть запрещено использовать конструктор копирования . Это предложение мое внимание привлекла в §12.8/32, который, кажется, указывает, что конструктор копирования должен быть рассмотрен в разрешении перегрузки:

Если первое разрешение перегрузки не может или не была выполнена, или если Тип первого параметра выбранного конструктора не является ссылкой на тип значения , относящимся к типу объекта (возможно, cv-qualified), . Реализация перегрузки выполняется снова, рассматривая объект как lvalue.

Редактировать

От одного из комментариев T.C. ниже, я понимаю, что, когда объект, подлежащий копированию, обозначен RValue, компилятор, согласно §12.8/32, не делает рассмотрите конструктор-копию в качестве кандидата на копию, хотя копия будет отодвинута в любом случае. То есть конечным результатом будет построение объекта s со стандартным конструктором. Вместо этого в этой ситуации стандарт обязывает (где?) Код плохого формирования. Если мое понимание этой схемы совершенно неверно, это не имеет для меня никакого смысла.

+3

Разрешение перегрузки не прерывается при обнаружении удаленной функции. Удаленные функции не являются * несуществующими *, они в некотором смысле * не удалены *. Они просто * незаконны для вызова * (их можно вызвать, и если вы это сделаете, это ошибка). – dyp

+2

И в любом случае эта цитата из 12.8/32 не применяется. –

+0

@ T.C. ___ Почему нет? –

ответ

1

Это не имеет ничего общего с копиями или конструкторами; это просто разрешение перегрузки.

Если мы имеем пару перегрузок:

void f(T&& rv); 
void f(const T& lv); 

то правила в разрешении перегрузки сказать, что f(T{}) лучше подходит для f(T&&).

Копирование эльфийского текста может привести к копированию или перемещению, но только в том случае, если код четко определен (даже если компилятор решил не выполнять копирование). Ваш код не определен, потому что он указывает на вызов удаленной функции.

+0

Но почему удаленная функция должна участвовать в разрешении перегрузки? –

+0

@ François-MarieArouet, вот как это. В этом случае он выглядит более гибким: вы можете либо определить конструктор перемещения как удаленный, либо опустить его, и в этом случае он не будет существовать, и будет вызываться конструктор копирования. –

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

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