В каких ситуациях эта разница актуальна?
Когда хотя бы один аргумент фактически является lvalue (например, identity
, фактически).В этом случае соответствующий Fi
является T&
, то есть ссылкой на lvalue.И нельзя указывать ссылку lvalue в качестве основы для любого класса, поэтому std::decay
требуется для удаления всех ссылок и cv-квалификаторов.Когда руководство по выводу принимает аргументы по значению, это автоматически не проблема.Это связано с тем, что вычет аргументов шаблона для типов значений уже «разлагает» типы.
Если вам интересно, какой использовать, то я бы сказал, что тот, у которого меньше помех, объективно лучше.Использование std::decay_t
предназначено для получения того же поведения, которое было бы с версией по значению, так что можно также использовать это.
Почему вы хотите определить функцию тождества ниже свернуть decltype (x) (x), а не просто вернуть x
Это форма переадресации.Так как тип возвращаемого значения лямбды объявлен как decltype(x)
, нам нужно, чтобы приведение было правильно привязано к ссылке rvalue.Потому что в случае decltype(x) = T&&
он не будет привязан только к x
, что является lvalue.
Можем ли мы считать foo(convert(std::forward<Args>(args))...)
совершенной пересылкой (для всех не преобразованных аргументов) простокак foo(std::forward<Args>(args)...)
Да.Аргументы к bar
уже привязаны к ссылкам.convert
позволяет этим ссылкам проходить с сохранением категории значения, так что это действительно переадресация.