Это ошибка GCC .
decltype(auto) = e
эквивалентно decltype(e)
и дает объявленный тип e
.
auto
работает как параметр шаблона, что означает, что auto&&
совпадает с T&&
(ссылка на пересылку) для изобретенного параметра шаблона.
Для f1 тип возвращаемого значения выводится на int
.
Для f2 тип возврата auto&
эквивалентен T&
с выведенным T=int
, который является типом lvalue e
, здесь вы привязываете int&
к e
.
Для f3 учтите это:
auto&& t = n;
static_assert(std::is_same_v<decltype(t), int&>); // true
для обоих возвращаемых значений f3
, auto&&
эквивалентно придуманному параметру шаблона T&&
, который является ссылкой для пересылки, который инициализируется lvalue,yield T&
с выведенным T=int
, затем снова ... привязка int&
к lvalue e
.
Теперь для f4 рассмотрим это:
int&& r = 9;
static_assert(std::is_same_v<decltype(r), int&&>); // true (1)
decltype(auto) t = r; // fail with the same error you got.
параметр f4
также является ссылкой для переадресации T&&
, которая инициализируется значением xvalue std::move(n)
, это выводит T=int
, что приводит караметр int&& e
.Тип возврата как decltype(auto)
с return e
означает, что фактическое возвращение равно decltype(e)
, тогда, как вы можете видеть (1), истинно, то же самое верно для decltype(e)
, это означает, что фактическое возвращение f4
это int&&
... и есть проблема, f4
пытается связать rvalue int&&
с lvalue e
, что запрещено.
Вы также можете взглянуть на @ StoryTeller ответ за ошибку в GCC.