Не имеет ли смысла объявлять тип возвращаемого значения функции как T & amp;?

Как мы знаем, в большинстве распространенных случаев T&& означает «это временный объект». Однако, если кто-то хочет вернуть временный объект из функции, он / она может объявить функцию следующим образом:

template<class T>
T f()
{
T t;
......

return t;
}

или (Примечание: не правильно)

template<class T>
T&& f()
{
T t;
......

return t;
}

Но я думаю, что последнее переусердствовало, потому что первое достаточно и обратно совместимо.

Тем не менее, я также нахожу std::forward()возвращаемый тип объявлен как T&&так что я уверен, что мое понимание этого неполно.

Мой реальный вопрос: когда и где мы должны объявить возвращаемый тип функции как T&&?

13

Решение

В вашем примере 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».

13

Другие решения

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);}
4

Ответ зависит от того, является ли ваша функция функцией шаблона или нет. В вашем вопросе это было, но давайте сначала посмотрим, если это не так:

Нешаблонном

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, если это ..

2
По вопросам рекламы [email protected]