Почему ошибка в параметре типа ссылка?

Рейтинг: 1Ответов: 2Опубликовано: 19.02.2023
class m {
public:

    int n;
    m(int n) :n(n) {};
    m(m& nn) {
        n = nn.n;
    }
    m operator=(m& ex);
};

m m::operator=(m& ex) {
    this->n = ex.n;
    return n;
}

m f() {
    m k(8);
    return k;
}

ostream& operator<<(ostream& os, m& ex) {
    os << ex.n<<endl;
}

int main() {
    m m1(1), m2(2);

    m1 = f();//вернулся тип m, а дальше просто как обычная передача
             //параметра по ссылке, чтобы не занимать место
    cout << m1;
    
}

почему ошибка=бинарный "=": не найден оператор, принимающий правый операнд типа "m" (или приемлемое преобразование отсутствует)

есть же такое

int foo(int& v){
++v;}

int main(){
int x=9;
foo(x)// здесь же тоже не ссылочный тип 

}

Ответы

▲ 2Принят
m1 = f();

Здесь вызывается оператор присваивания, у вас имеющий вид

m m::operator=(m& ex) {
    this->n = ex.n;
    return n;
}

Заметим, что ваша функция m f() возвращает значение (временное) типа m. А объявление оператора присваивания ясно говорит, что при присваивании присваиваемый аргумент может изменяться, он не константный. То, что он не изменяется — это неважно, важно, что своим (m& ex) вы оставляете такую возможность.

Чтобы было понятнее, представьте себе, что это int, функция возвращает, например, 2, но при присваивании это 2 должно изменяться. Но ведь переменной, которая бы хранила двойку, просто нет! Так понятнее?

Вот если бы вы объявили (оставим возврат еще одного временного объекта m после присваивания на ваше усмотрение, заметим только, что это лишает вас возможности использовать цепочку присваивания `a = и = сё)

m m::operator=(const m& ex)

то тогда дело другое.

В примере с int дело другое:

int foo(int& v) { ++v; }

int main(){
    int x=9;
    foo(x);
}

x, будучи переменной, запросто превращается в ссылку. А вот попробуйте вызвать здесь foo(4) — и вы увидите, что это не работает. Или хотя бы foo(foo(x)).

Формальный ответ вам дал user7860670 в комментариях, я же постарался просто расписать его понятнее.

▲ 2

Аргумент m & ex в m operator=(m& ex); может быть предоставлен только объектом со стабильным временем жизни lvalue. А возвращаемое значение функции m f() возвращает всегда временное значение rvalue.
Ссылки на эти типы несовместимы и надо отдельно писать разные функции. Вариант универсальности будет если аргумент константный.

Только для lvalue :

m operator=(m & ex);

Только для rvalue :

m operator=(m && ex);

Для всех :

m operator=(m const & ex);