Какие проблемы не для пересылки универсальной ссылки?

Насколько я знаю, в C ++ 11 универсальная ссылка всегда должна использоваться с std::forward, но я не уверен, какая проблема может возникнуть, если std::forward не используется

template <T>
void f(T&& x);
{
// What if x is used without std::forward<T>(x) ?
}

Не могли бы вы привести примеры проблем, которые могут возникнуть в этой ситуации?

10

Решение

Есть нет такого правила в всегда использование std::forward с универсальные ссылки. Наоборот, это может быть опасно для использования std::forward повсюду в функциях с универсальные ссылки. Взгляните на следующий пример:

template <typename T>
auto make_pair(T&& t)
{
return std::make_tuple(std::forward<T>(t), std::forward<T>(t)); // BAD
}

Если вы вызываете эту функцию с make_pair(std::string{"foobar"})результат нелогичен, потому что вы перемещаетесь с одного и того же объекта дважды.


Обновить: Вот еще один пример, чтобы показать, что это действительно имеет смысл использовать универсальные ссылки без идеальная пересылка:

template <typename Range, typename Action>
void foreach(Range&& range, Action&& action)
{
using std::begin;
using std::end;
for (auto p = begin(range), q = end(range); p != q; ++p) {
action(*p);
}
}
  • Хорошо что спектр это универсальная ссылка, так что звонящий может использовать для каждого с временным контейнером и действием, которое вызывает неконстантная функция-член на элементах.
  • Хорошо что действие это универсальная ссылка, так что абонент может передать изменчивое лямбда-выражение как действие.
  • И было бы неправильно использовать std::forward за спектр или для действие.
16

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

Скажем f называется так:

f(someType{});

Если тело f выполняет какую-то операцию на x

foo(x);

и есть две перегрузки для foo

void foo(someType const&);

void foo(someType&&);

без использования std::forward, как x является lvalue, следующая перегрузка называется

void foo(someType const&);

что может стоить вам потенциальной оптимизации.

С помощью

foo(std::forward<T>(x));

обеспечивает правильную перегрузку foo выбран.

10

Вещи с именем являются lvalues. Это означает, что в теле функции, t это значение. Не имеет значения, является ли универсальная ссылка константой lvalue или ссылкой rvalue. Если это имя, это lvalue.

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

В ситуации, когда вы хотите просто передать непрозрачный аргумент другой функции, вы хотите передать его в точности как есть. Если это было lvalue, вы хотите передать его как lvalue; если это было значение, вы хотите передать значение. Как объяснено, прохождение этого непосредственно передает это как lvalue всегда. forward магия, необходимая, чтобы передать это как правильную ценность,

Код, который всегда проходит через lvalue, скорее всего, будет страдать с точки зрения производительности, но я бы сказал, что вы можете игнорировать это, думая об этой конкретной проблеме. Существует более насущная проблема не всегда передавать lvalue: в то время как копирование некоторых типов может быть дорогим, некоторые другие типы не могут быть скопированы совсем, лайк std::unique_ptr, Для этих типов сохранение rvaleness при пересылке зависит не от производительности, а от того, чтобы ваш код даже компилировался.

6

Вы не должны пересылать переменную более одного раза.

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