Когда дан код следующей структуры
template <typename... Args>
void foo(Args&&... args) { ... }
Я часто видел, как библиотечный код использует static_cast<Args&&> внутри функции для пересылки аргументов. Как правило, это оправдывается тем, что использование static_cast позволяет избежать ненужного создания экземпляра шаблона.
С учетом свертывания языковой ссылки и правил вывода шаблонов. Мы получаем идеальную пересылку с static_cast<Args&&>, доказательство для этого утверждения ниже (в пределах полей ошибок, которые, я надеюсь, ответ просветит)
- Когда даны ссылки на rvalue (или для полноты - нет ссылки на квалификации, как в этом примере), это сворачивает ссылки таким образом, что результатом является rvalue. Используется правило
&& &&→&&(правило1выше) - Когда даны ссылки на lvalue, это сворачивает ссылки таким образом, что результатом является lvalue. Здесь используется правило
& &&→&(правило2выше)
По сути, это заставляет foo() пересылать аргументы в bar() в приведенном выше примере. Это поведение, которое вы получите при использовании std::forward<Args> здесь.
Вопрос - зачем вообще использовать std::forward в этих контекстах? Оправдывает ли отказ от дополнительной инстанциации нарушение соглашения?
В статье Говарда Хиннанта n2951 указано 6 ограничений, при которых любая реализация std::forward должна вести себя "правильно". Это были
- Следует переслать lvalue как lvalue
- Следует переслать rvalue как rvalue
- Не следует пересылать значение как значение
- Должны пересылать менее квалифицированные cv выражения в более квалифицированные cv выражения
- Должен ли перенаправлять выражения производного типа в доступный однозначный базовый тип
- Не следует пересылать произвольные преобразования типов
(1) и (2) было доказано, что правильно работает со static_cast<Args&&> выше. (3) - (6) здесь не применимы, потому что когда функции вызываются в выведенном контексте, ничего из этого не может произойти.
Примечание: я лично предпочитаю использовать std::forward, но у меня есть оправдание только потому, что я предпочитаю придерживаться соглашения.