Когда использовать std :: forward для пересылки аргументов? - PullRequest
146 голосов
/ 31 августа 2011

C ++ 0x показывает пример использования std::forward:

template<class T>
void foo(T&& arg) 
{
  bar(std::forward<T>(arg));
}

Когда выгодно использовать std::forward, всегда?

Также требуется использование && в декларации параметров, это действительно во всех случаях?Я думал, что вам нужно передать временные функции в функцию, если функция была объявлена ​​с &&, поэтому можно ли вызывать foo с любым параметром?

Наконец, если у меня есть вызов функции, такой как этот:

template<int val, typename... Params>
void doSomething(Params... args) {
  doSomethingElse<val, Params...>(args...);
}

Должен ли я использовать это вместо этого:

template<int val, typename... Params>
void doSomething(Params&&... args) {
  doSomethingElse<val, Params...>(std::forward<Params>(args)...);
}

Кроме того, целесообразно ли использовать параметры в функции дважды, например, переадресацию на две функции одновременно, целесообразно использовать std::forward?Разве std::forward не преобразует одно и то же во временное дважды, перемещая память и делая ее недействительной для повторного использования?Будет ли следующий код в порядке:

template<int val, typename... Params>
void doSomething(Params&&... args) {
  doSomethingElse<val, Params...>(std::forward<Params>(args)...);
  doSomethingWeird<val, Params...>(std::forward<Params>(args)...);
}

Я немного смущен std::forward, и я бы с удовольствием воспользовался некоторыми разъяснениями.

1 Ответ

114 голосов
/ 31 августа 2011

Используйте его, как в первом примере:

template <typename T> void f(T && x)
{
  g(std::forward<T>(x));
}

template <typename ...Args> void f(Args && ...args)
{
  g(std::forward<Args>(args)...);
}

Это из-за правил свертывания ссылок : если T = U&, то T&& = U&, но если T = U&&, тоT&& = U&&, так что вы всегда получаете правильный тип внутри тела функции.Наконец, вам нужно forward, чтобы превратить lvalue-превращенный x (потому что у него теперь есть имя!) Обратно в ссылку на rvalue, если она была изначально.

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

...