Зачем нужно пересылать возвращаемое значение - PullRequest
8 голосов
/ 02 июня 2019

В doc из std::forward он дал следующий пример:

template<class T>
void wrapper(T&& arg)
{
    foo(forward<decltype(forward<T>(arg).get())>(forward<T>(arg).get()));
}

Зачем здесь переадресация возвращаемого значения? В каких случаях он отличается от следующего кода:

template<class T>
void wrapper(T&& arg)
{
    foo(forward<T>(arg).get());
}

Ответы [ 2 ]

5 голосов
/ 02 июня 2019

Давайте разберемся с возможностями. T::get может вернуть ссылку lvalue (которая является выражением lvalue), ссылку rvalue (которая является выражением xvalue) или значение prvalue.

Выражение forward преобразует выражение lvalue в ... выражение lvalue. Это преобразует xvalue в ... xvalue. И он преобразует prvalue в xvalue.

Правила C ++ относительно того, как аргументы связываются с параметрами в разрешении перегрузки, одинаковы для выражений prvalue и xvalue. Поэтому последние два всегда будут вызывать одну и ту же функцию.

Следовательно, внешнее forward ничего не достигает. Действительно, это хуже , чем вообще ничего не делать. Почему?

Потому что значения в C ++ 17 и выше имеют гарантированное исключение; xvalues ​​ не . Если foo принимает параметр по значению, дополнительный forward покажет ненужный временный объект, который затем будет перемещен в аргумент. Если тип является чем-то более сложным, чем int, тогда есть неплохой шанс, что вы потеряете некоторую производительность.

Так что не пересылайте возвращаемые значения, которые вы собираетесь передать непосредственно в качестве аргументов функции. Если вам нужно сохранить значение в промежуточной переменной auto&&, то вам нужно это переслать. Но если вы делаете это на месте, как это, не надо.

3 голосов
/ 02 июня 2019

Правка, добавленная в , утверждает, что это пример второй перегрузки:

template< class T >
constexpr T&& forward( typename std::remove_reference<T>::type&& t ) noexcept;

Пример не очень хороший, так как уже является значением. На самом деле я не думаю, что вторая перегрузка настолько полезна, за исключением создания:

std::forward<decltype(expression)>(expression);

работает для всех выражений (включая, если expression является r-значением), но большинство случаев использования для std::forward ограничиваются l-значениями T&& и auto&&.

...