В чём смысл std::forward при передаче параметров?

164
03 сентября 2021, 03:20

В чём разница между следующими двумя способами передачи параметров?

template <typename ...Args> smth(Args &&...args) : base(args...) {}
template <typename ...Args> smth(Args &&...args) : base(std::forward<Args>(args)...) {}
Answer 1

Предположим, что конструктор base принимает move-only параметр по значению:

struct base {
  base(std::unique_ptr<int> value);
};

В таком случае первый вариант не скомпилируется:

template <typename ...Args> smth(Args &&...args) : base(args...) {}
                                  попытка сделать копию ^^^^

Тут можно написать std::move и это будет работать:

template <typename ...Args> smth(Args &&...args) : base(std::move(args)...) {}

Однако в случае если у base два конструктора, один из которых перемещает значение, а другой принимает ссылку:

struct base {
  base(std::unique_ptr<int>&& value);
  base(std::unique_ptr<int>& value);
};

И если мы хотим чтобы smth передавал в base именно те типы аргументов, с которыми его вызвали, то std::move нам не подойдет - он всегда будет превращать аргумент в r-value ссылку.

Для этого есть std::forward<T>, который сохраняет оригинальный тип аргумента:

struct smth : base {
  template <typename ...Args> smth(Args &&...args) : base(std::forward<Args>(args)...) {}
};
std::unique_ptr<int> p;
smth s1(p);            // OK, будет вызван base(std::unique_ptr<int>&);
smth s2(st::move(p));  // OK, будет вызван base(std::unique_ptr<int>&&);

Примечание: std::forward<T>(t) работает только с "универсальнами ссылками", т.е. когда T - это параметр шаблона функции (конструктора), а t - аргумент этой функции с типом T&& (это специальное исключение в языке, такой тип T&& не является r-value ссылкой, а заставляет T повторять тип того, что передали в функцию).

READ ALSO
Время на растягивание объекта ризинка

Время на растягивание объекта ризинка

Не совсем правильно растягивается, как сделать более плавно и что нужно поправить или добавить?

185
Замена иконки окна из внешней DLL

Замена иконки окна из внешней DLL

Есть консольное приложение, которое вызывает метод в сторонней DLLМетод открывает новое окно с дефолтной иконкой Windows

161
Nullable- это больше, чем структура?

Nullable- это больше, чем структура?

В общем, интереса ради залез в исходники Nullable<T> и увидел вот такое:

92