Как мы знаем, в большинстве распространенных случаев T&&
означает «это временный объект». Однако, если кто-то хочет вернуть временный объект из функции, он / она может объявить функцию следующим образом:
template<class T>
T f()
{
T t;
......
return t;
}
или (Примечание: не правильно)
template<class T>
T&& f()
{
T t;
......
return t;
}
Но я думаю, что последнее переусердствовало, потому что первое достаточно и обратно совместимо.
Тем не менее, я также нахожу std::forward()
возвращаемый тип объявлен как T&&так что я уверен, что мое понимание этого неполно.
Мой реальный вопрос: когда и где мы должны объявить возвращаемый тип функции как T&&?
В вашем примере T&&
это неправильно, это свисающая ссылка.
Но std::forward
не возвращает ссылку rvalue на локальную переменную в своем собственном определении, она возвращает ссылку rvalue на свой аргумент by-rvalue-reference (или ссылку lvalue на аргумент by-lvalue-reference).
Вы должны возвращать ссылку на rvalue, только если вы хотите, чтобы вызывающая сторона вашей функции могла двигаться от того, на что ссылается эта ссылка.
Обычно это происходит только в том случае, если целью функции является предоставление доступа к некоторому значимому объекту (возможно, который уже существует). Так что включает в себя std::move
(который позволяет вам перейти от lvalue), и аналогичным образом вы можете написать функцию доступа, специально предназначенную для пользователей, чтобы переходить от элемента данных какого-либо объекта или элемента некоторого контейнера. Если сам объект не имеет значения, только значение, то вы можете вернуть по значению.
Как говорит гризли, иногда из-за свертывания ссылок вы можете воспользоваться трюками, которые означают, что вы тип T&&
в вашем коде, но когда T
это уже тип lvalue-reference T&&
тот же тип ссылки lvalue. std::forward
использует этот трюк. То есть из-за разрушения ссылки T&&
не означает «rvalue ссылка на T», это означает «T, если T является ссылочным типом, в противном случае rvalue ссылка на T».
T&&
не обязательно означает, что результатом является значение. При использовании с параметром шаблона &&
обозначает универсальную ссылку, которая может быть либо ссылкой rvalue, либо ссылкой lvalue. Более конкретно: если T
тип ссылки lvalue foo&
, T&&
на самом деле lvalue ссылаются на foo
в противном случае он обозначает ссылку на значение.
Это может быть использовано для написания функций, которые принимают любые аргументы:
template<typename T> void foo(T&&);
bar a;
const bar b;
foo(a);//T and T&& will both be bar&
foo(b);//T and T&& will both be const bar&
foo(bar());//T will be bar, T&& will be bar&&
Имея это в виду std::forward
называется с T&
и бросает это T&&
, где T
четко указано. Таким образом, если исходный параметр функции был ссылкой на lvalue, он вернет его, в противном случае он вернет ссылку на rvalue, что обеспечивает идеальную пересылку.
Что касается того, когда использовать его в качестве возвращаемого типа: Редко, хотя может быть полезно избегать копий при передаче аргументов, например:
template<typename T> T&& foo(T&& bar) {/*some ops*/ return std::forward<T>(bar);}
Ответ зависит от того, является ли ваша функция функцией шаблона или нет. В вашем вопросе это было, но давайте сначала посмотрим, если это не так:
Нешаблонном
T&&
не имеет смысла в качестве возвращаемого типа. Причина в том, что это, по сути, не означает «временный объект». Это означает «ссылка на значение». Разница невелика, но может быть выделена с помощью класса функций, для которых этот тип возврата является релевантным. А именно, что если мы хотим вернуть ссылку на значение, но объект, на который она ссылается, не является локальным объектом нашей функции?
T&& return_rvalue(/*some data*/)
{
T&& t = Get_a_reference();
// Do something fascinating.
return static_cast<T&&>(t);
}
Одним из особых случаев этого паттерна является функция std::move
, который берет любую ссылку и возвращает ей соответствующую ссылку. Естественно, в реальном коде вы должны, конечно, использовать std::move
вместо того, чтобы выполнять бросок напрямую, так как это более ясно показывает ваше намерение.
шаблон
Если T
это параметр шаблона, T&&
это то, что Скотт Мейерс называет Универсальная ссылка. Это означает тип T&&
будет вычисляться с помощью свертывания ссылок … Короче, это значит T&&
это значение, если T
я не ссылочный тип, а ссылка lvalue, если это ..