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

#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. Есть ли решение этой проблемы?