Можно ли использовать функцию с квалификацией lvalue-ref непосредственно в функции с квалификацией rvalue-ref? - PullRequest
2 голосов
/ 26 мая 2020

Я писал следующий код для поддержки вызовов функций для rvalues ​​без необходимости std::move явно возвращать значение.

struct X {
    X& do_something() & {
        // some code

        return *this;
    }

    X&& do_something() && {
        // some code

        return std::move(*this);
    }};

Но это приводит к необходимости повторения кода внутри функции. Желательно, чтобы я сделал что-то вроде

struct X {
    X& do_something() & {
        // some code

        return *this;
    }

    X&& do_something() && {
        return std::move(do_something());
    }};

Это правильное преобразование? Почему или почему нет?

Кроме того, я не могу не чувствовать, что есть некоторый пробел в знаниях относительно ref-квалификаторов. Есть ли общий способ (или набор правил) выяснить, действителен ли подобный код или нет?

1 Ответ

3 голосов
/ 26 мая 2020

Это допустимое преобразование?

Да. Внутри функции-члена *this всегда имеет lvalue. Даже если функция квалифицирована по ссылке rvalue. Это то же самое, что и

void foo(bar& b) { /* do things */ }

void foo(bar&& b) {
  // b is an lvalue inside the function
  foo(b); // calls the first overload
}

. Таким образом, вы можете использовать функцию с определением lvalue ref для совместного использования реализации.

И использование std::move в результате также не проблема. Первая перегрузка может вернуть только ссылку lvalue, потому что, насколько ей известно, она была вызвана для lvalue. Между тем, вторая перегрузка имеет дополнительный бит информации, она знает, что изначально была вызвана для rvalue. Следовательно, он выполняет дополнительное приведение на основе дополнительной информации.

std::move - это просто именованное приведение, которое превращает lvalue в rvalue. Его цель состоит в том, чтобы указать, что назначенный объект может рассматриваться как истекающий. Поскольку вы выполняете это приведение внутри контекста, о котором вы знаете, что это правда (член изначально вызывается для объекта, который привязывается к ссылке rvalue), это не должно создавать проблемы.

...