Ответ 1
Этот ответ основан на моей интерпретации соответствующего стандартного текста. Эти разделы не очень ясны из-за разделенных мнений, и поэтому в настоящее время трудно понять их точное значение. Похоже, что, исключая возможный надзор, основные компиляторы, похоже, согласны с тем, что данное определение действительно хорошо сформировано.
Кроме того, я считаю, что было бы очень удивительно услышать, что это определение было плохо сформировано.
Причина шока, который я испытал, лежит в стандарте, в котором конкретно говорится, что лямбда не должна встречаться в неоцененном операнде [...]
Где вы видите, что лямбда появляется в неоценимом контексте?
decltype(auto) lambda = [](){};
Я не вижу этого, потому что его нет. Лямбда используется как инициализатор, который полностью легален.
Теперь ваше замешательство, вероятно, происходит, потому что вы, кажется, думаете, что приведенное выше утверждение эквивалентно
decltype([](){}) lambda = [](){};
Это не так, строго говоря. Если вы посмотрите на язык формулировки, есть небольшая разница (выделено мной):
Если заполнителем является спецификатор типа
decltype(auto)
,T
должен быть только заполнителем. Тип, выведенный дляT
, определяется, как описано в [dcl.type.simple], поскольку хотяe
был операндомdecltype
.
Ключевое слово здесь. Это просто означает, что вывод происходит так, как если бы он был decltype(e)
, что означает, что правила вывода decltype
применяются вместо тех, что для auto
для операнда e
.
Здесь операнд e
действительно является лямбдой, но это полностью законно, потому что в Стандарте указано, что поведение такое же, как если бы вы написали decltype([](){})
, что означает правила правил decltype
вычет применяется для лямбда. Теперь [expr.prim.lambda]/2
здесь не применяется, поскольку лямбда не находится в необоснованном контексте, поэтому для компилятора фактически использовать decltype([](){})
для вывода типа, что означает, что правила decltype
должны использоваться для лямбда.
Конечно, если вы пишете decltype([](){})
, программа плохо сформирована, но здесь это не так, как упоминалось выше.
В этом случае, поскольку выражение лямбда является prvalue, выводимый тип должен быть просто типом лямбда.
По крайней мере, как я это понимаю...