Perfect forwarding на пальцах — это когда ты пишешь шаблонную функцию-обёртку, в которую может прийти объект произвольного типа, и тебе нужно передать этот объект дальше, полностью сохранив его тип и ссылочную категорию (если тебе передали T &, то нужно вызвать вложенную функцию от T &, если передали T && — то нужно вызвать вложенную функцию от T &&). Отсюда perfect.
Потому что не нужно слушать идиотов. Вернее кто-то, возможно, даже говорил что-то вменяемое, но в момент передачи что-то поломалось.
Никакой передачи, никакой forward не нужен и никакой move тут вообще не причём. И никакой move ничего не теряет.
Условно, для птушников. macdak << lzzz - это move в макдак, а вот это форвард if(!zachetka) macdak << lzzz. Соответственно, move тебя сразу в макдак отправит, а forward посмотрит зачётку. Это просто две разные операции с разной семантикой. Общее в них то, что move является составной частью forward, но никак не означает, что move что-то там теряет.
Но не особо видно, что forward тебе нужен. Поэтому можно забить. move - это будущие.
Потому что базовая семантика языка. Передача аргумента, условно, ничем не отличается от присваивания.
Очевидно, что в ситуации:
T r = 123;
auto && r1 = r;
// Здесь r == 0
Ты не хочешь терять данные в изначальном объекте. Автоматически это работает тогда, когда объект, который ты присваиваешь, временный. На него нет ссылок и тебе насрать что с ним станет.
А вот если на него ссылка есть - ты не хочешь терять в нём данные.
СМ. мой пример выше. Он должен отличить при инстанцировании шаблона string & от string && и для первого сделать копирование, а для второго перемещение, что тебе непонятно?
Я даже тебе отвечу, попытавшись твои потуги свести к чему-то минимально-вменяемому.
Действительно, forward можно выкинуть добавив возможности к языку, но, опять же, это нужно в любом случае что-то сделать - самом оно работать в принципе не может.
И вот уже проблема C++. В С++(и особенно в других языках) нету нормальных функций, нету семантического инлайна(который и решает в том числе эту проблему).
И никогда эта проблема не будет решена ни в С++, ни в других языках.
Во-первых я не обязан следить за твоими потоками шизофазии, а во-вторых - это полная чушь. Пример дерьмо и ничего не показывает. Сообщи для начала - что он должен мне сообщить. Что из него следует?
И да, осиль C++ и нормальный стиль. Читать бездарный мусор мне противно.
Зачем? Это для тебя они - хозяева. Для меня они - птушники.
Например, нельзя будет скомпилировать старые программы, или что то еще?
Нет, причём тут старые программы? У тебя плохо с логикой. Существуют языки для которых нет старых программ.
Значит причина где-то на фундаментальном уровне. Объяснить её птушнику - не представляется возможным. Просто запомни это. Там, где есть функции - такого поведения нет и быть не может.
Ты не думал - почему forward в С++ выглядит как говно? Зачем туда тип? Правильно, потому что функции говно.
В общем, ради пацанов даже объясню. https://godbolt.org/z/AdVVXe - вот «функции» с семантическим инлайном. Если попроще, то это что-то типа макросов.
И здесь ты можешь реализовать ИСТИННЫЙ pf(в крестах он фейковый, на самом деле. А в других недоязычках его вообще нет). Так же можешь реализовать forward, который невозможно реализовать на С++ без костылей.
После второго вызова overloaded() строка x будет мусором, мы хотим забрать у неё ресурс самым последним этапом, перед этим будем как-то пользоваться её, куда-то передавать, а под конец «грохним». Для этого и нужен «костыль» std::forward - выбрать этот момент (но лишь тогда, когда fn попало rvalue). Естественно, компилятор не знает чего ты там задумала. Ну и да, один общий код для rvalue/lvalue.