ошибка: неоднозначная перегрузка для 'operator =' в функции подкачки, использующей идиому копирования и замены - PullRequest
1 голос
/ 04 ноября 2019

При использовании идиомы для копирования и замены *1002* в классе с постоянными ссылками в качестве членов возникает вышеуказанная ошибка.

Пример кода:

#include <iostream>
#include <functional>

using std::reference_wrapper;

class I_hold_reference;
void swap(I_hold_reference& first, I_hold_reference& second);

class I_hold_reference{
    inline I_hold_reference(const int& number_reference) : my_reference(number_reference){}
    friend void swap(I_hold_reference& first, I_hold_reference& second);
    inline I_hold_reference& operator=(I_hold_reference other){
        swap(*this, other);
        return *this;
    }
    inline I_hold_reference& operator=(I_hold_reference&& other){
        swap(*this, other);
        return *this;
    }
private:
    reference_wrapper<const int> my_reference;
};

void swap(I_hold_reference& first, I_hold_reference& second){
    first = I_hold_reference(second.my_reference); //error: use of overloaded operator '=' is ambiguous (with operand types 'I_hold_reference' and 'I_hold_reference')
}

Когда оператор присваивания Копии изменяется для получения аргумента по ссылке, а не по значению, ошибка исправляется.

    inline I_hold_reference& operator=(I_hold_reference& other){ ... }

Почему это исправляет ошибку? Одним из возможных последствий может быть то, что Важная возможность оптимизации , на которую есть ссылка в связанном вопросе, потеряна. Это было когда-либо верно для ссылок? Каковы другие последствия этого изменения?

Существует кодовая база, полагающаяся на этот оператор, никаких других членов нет, только упомянутые ссылки. Есть ли необходимость каким-то образом адаптировать кодовую базу к этим изменениям, или это безопасно как есть?

Ответы [ 2 ]

4 голосов
/ 04 ноября 2019

Если вы внимательно следите за описанием, которое вы связали, вы увидите, что у вас должна быть только одна перегрузка operator=, и что нужно принимать аргумент по значению. Таким образом, простое устранение перегрузки operator=(I_hold_reference&&) сделает ваш код компилируемым.

Однако это не единственная проблема. Ваш swap не поменяется! Вместо этого он назначает копию second для first и оставляет second нетронутым.

Это то, что вы хотите:

class I_hold_reference
{
    I_hold_reference(const int& number_reference)
     : my_reference(number_reference){}

    friend void swap(I_hold_reference& first, I_hold_reference& second)
    {
        using std::swap;
        swap(first.my_reference, second.my_reference);
    }

    I_hold_reference& operator=(I_hold_reference other)
    {
        swap(*this, other);
        return *this;
    }
private:
    reference_wrapper<const int> my_reference;
};

Примечание: я удалил ненужные inlines как функции-члены неявно встроены. Также я объявил функцию swap внутри вашего класса. Вы можете найти объяснение этому в ссылке, которой вы поделились.

Кроме того, в этом конкретном примере использование идиомы копирования и замены не является необходимым в первую очередь. std::reference_wrapper не является обслуживаемым вручную ресурсом, а это означает, что в него встроена надлежащая семантика копирования и перемещения. Поэтому в этом конкретном примере сгенерированные компилятором операторы копирования и перемещения будут работать точно так же, как и созданные вручную. Таким образом, вы должны использовать их, а не писать свои собственные каким-либо образом. С другой стороны, если это всего лишь игрушечный пример и в реальном классе ресурсов * на 1020 * больше, которые требуют ручного управления, то это путь.

1 голос
/ 04 ноября 2019

Использование ссылки переадресации && будет привязано к любому значению rvalue ( временные данные / ссылки пересылки ). Эти категории также могут быть переданы как значения, и тогда они неоднозначны. То есть, например, временный является неоднозначным, когда lvalue не будет (используется перегрузка значения).

Где, поскольку неконстантная ссылка никогда не может связываться с временным или ссылка на пересылку . Ссылка const может, хотя и не двусмысленно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...