Возвращаемое значение или значение rvalue?

В новой книге Скотта Мейера он предлагает пример использования для спецификаторов ссылок rvalue, которые выглядят примерно так:

class Widget {
private:
    DataType values;

public:
    DataType& data() &  { return values; } 
    DataType  data() && { return std::move(values); } // why DataType?
};

Итак, чтобы:

auto values = makeWidget().data();

move-constructs values вместо копирования-конструирования.

Почему rvalue-ref-qual data() возвращает DataType вместо DataType&&? auto все равно выводит DataType в этом случае (хотя decltype(auto) не будет - но это не может быть единственной причиной, чтобы предпочесть возвращать значение вместо ravlue ref). Этот одобренный ответ возвращает rvalue ref, что делает меня концептуально понятным.

Ответ 1

DataType data() && { return std::move(values); } // why DataType?

auto values = makeWidget().data();

Временное значение, которое содержит возвращаемое значение, будет инициализироваться с помощью конструктора move, инициализированного с помощью move(values).

Затем это временное инициализирует values, но поскольку makeWidget().data() является rvalue (то есть, чтобы быть точным), конструктор move вызывается снова - с временным аргументом.

Теперь рассмотрим copy-elision:

Когда безымянный временный, не привязанный к каким-либо ссылкам, будет перемещен или скопированы в объект того же CV-неквалифицированного типа, copy/move опущен. Когда это временное построено, оно построенный непосредственно в хранилище, где он был бы перемещен или скопированы. Когда безымянный временный является аргументом возврата оператор, этот вариант копирования является известным как RVO, "возвращаемое значение оптимизация".

Итак, второе движение (предположительно) будет полностью устранено, и останется только один - тот, который у нас был бы в любом случае, если тип возврата был ссылкой на rvalue.

Проблема с возвратом ссылки rvalue заключается в том, что если мы пишем

auto&& values = makeWidget().data();

values будет болтаться, поскольку привязка значения x к ссылке не продлевает время жизни anythings. Когда мы возвращаем тип объекта, время жизни увеличивается.

Ответ 2

auto&& будет разбит, если он вернет ссылку rvalue. Связанный ответ разбит в этом конкретном случае.

Основная проблема заключается в том, что вы можете перегружать lvalue или rvalue, но есть три категории значений, которые вы, возможно, захотите узнать о значении, lvalue и rvalue. С++ не различает значение и rvalue при вызове функций-членов, поэтому вы не можете знать, правильно ли оно вернет ссылку rvalue или нет. Независимо от того, какое решение вы принимаете, легко построить примеры, где это не сработает.