Когда использовать std:: forward для пересылки аргументов?
С++ 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
Используйте его, как ваш первый пример:
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-turn x
(потому что теперь он имеет имя!) Обратно в ссылку rvalue, если она была изначально.
Вы не можете пересылать что-то более одного раза, хотя это не имеет смысла. Пересылка означает, что вы потенциально перемещаете аргумент до последнего вызывающего, и как только он его переместит, вы не сможете использовать его снова.