#c #g #move-semantics
#c #g #перемещение-семантика
Вопрос:
Если я определю оператор присваивания копирования, который вызывает конструктор копирования, используя передачу по значению для класса thing
:
thingamp; operator= (thing x) {
и оператор присваивания перемещения для того же класса:
thingamp; operator= (thingamp;amp; x) {
Попытка вызвать назначение перемещения приводит к ошибке gcc:
error: ambiguous overload for ‘operator=’ (operand types are ‘thing’ and ‘std::remove_reference<thingamp;>::type {aka thing}’)
Однако, если вместо присвоения копии используется передача по ссылке:
thingamp; operator= (thingamp; x) {
Компиляция проходит нормально, и могут быть вызваны оба оператора. Почему это так?
Завершите тестовый код C 11:
#include <iostream>
#include <utility>
using namespace std;
class thing {
public:
thing () { }
thing (thingamp; x) {
cout << "Copy constructor.n";
}
thing (thingamp;amp; x) {
cout << "Move constructor.n";
}
thingamp; operator= (thing x) {
cout << "Copy assign using pass by value.n";
return *this;
}
thingamp; operator= (thingamp;amp; x) {
cout << "Move assign.n";
return *this;
}
};
int main (void) {
thing a, b;
// Invoke move assignment:
a = move(b);
return 0;
}
Комментарии:
1. В разрешении перегрузки есть специальное правило, к которому значения типа
A
предпочитают привязыватьсяAamp;amp;
, а неAamp;
. Для vs нет соответствующего правилаAamp;amp;
A
.2. @T.C. Не
Aamp;
обязательно должно быть значением lvalue ?3. На самом деле да, я должен был написать
const Aamp;
.Aamp;
привязывает только значения lvalues.
Ответ №1:
- Вызов
move(b)
возвращаетrvalue
. - Оба
operator=(thing amp;amp;x)
иoperator=(thing x)
могут приниматьсяrvalues
в качестве входных данных. - Таким образом, две перегрузки неоднозначны, и компилятор справедливо жалуется, потому что он не может выбирать между ними.
Комментарии:
1. 1 Я получаю второй пункт (о rvalues в качестве входных данных), но какова актуальность первого?
2. @goldilocks неоднозначный вызов —
a = move(b);
это то же самое, что и вызовa.operator=(move(b))
.std::move
возвращаетrvalue
ссылку, которая ссылается на его входные данные (т.Е.b
). Компилятор видит, что возвращаемое значениеstd::move
являетсяrvalue
ссылкой, и во время разрешения перегрузки пытается найти, какая перегрузка подходит для принятия в качестве входных данных результата, возвращаемогоstd::move
. К сожалению, как уже прокомментировал @T.C, нет правила, позволяющего различать две перегрузки. Следовательно, вы получаете неоднозначную ошибку вызова.3. Есть ли решение этой проблемы?