Если мы посмотрим на проект стандарта C ++ раздел 5.1.2
Лямбда-выражения параграф 2 говорит (Акцент шахты идет вперед):
Оценка лямбда-выражения приводит к временному значению prvalue (12.2). Этот временный объект называется объектом закрытия. Лямбда-выражение не должно появляться в неоцененном операнде (Пункт 5). [Примечание: закрывающий объект ведет себя как функциональный объект (20.8). — примечание конца]
и раздел 5.19
Постоянные выражения параграф 2 говорит:
Условное выражение является основным константным выражением, если он включает одно из следующего в качестве потенциально оцененного подвыражения (3.2), но подвыражения логических операций И (5.14), ИЛИ (5.15) и условных (5.16), которые не оцениваются, не рассматриваются […]
и имеет следующую пулю:
— лямбда-выражение (5.1.2);
Так почему же лямбда-выражения не допускаются в неоцененном операнде, но допускаются в неоцененных частях константных выражений?
Я могу видеть, как для неоцененных операндов информация о типе в нескольких случаях (decltype или же TypeId) не очень полезен, так как каждая лямбда имеет уникальный тип. Хотя почему мы хотели бы разрешить их в неизменном контексте постоянного выражения, неясно, возможно, чтобы учесть SFINAE?
Основная причина неоцененные операнды исключение кроется в Стандартные отчеты о дефектах основного языка C ++ и принятые проблемы # 1607. Лямбды в параметрах шаблона который стремится уточнить это ограничение и заявляет о намерении ограничения в разделе 5.1.2
было:
[…] предотвращение необходимости иметь дело с ними в сигнатурах шаблонов функций […]
Поскольку документация выпуска, текущая формулировка фактически имеет дыру, так как константные выражения позволяет им в неоцененном контексте. Но это не дает прямого объяснения этому ограничению. Желание избежать искажения имени выделяется, и вы можете сделать вывод, что избегая расширения SFINAE было также желательно, поскольку предлагаемая резолюция направлена на ужесточение ограничения, хотя несколько жизнеспособных альтернатив SFINAE. Модифицированная версия 5.1.2
параграф 2 следующее:
Лямбда-выражение не должно появляться в неоцененном операнде (пункт 5 [expr]), в аргументе шаблона, в объявлении псевдонима, в объявлении typedef или в объявлении функции или шаблона функции вне тела функции и аргументов по умолчанию [Примечание: цель состоит в том, чтобы не допустить появления лямбда-символов в сигнатуре — конец нота]. [Примечание: закрывающий объект ведет себя как функциональный объект (20.10 [function.objects]). —Конечная записка]
Это предложение было принято и находится в N3936
(см этот ответ для ссылки)
Для более ясного обсуждения обоснования, чтобы избежать использования лямбд в качестве неоцененный операнд. Обсуждение под названием Обоснование лямбда-выражений не допускается в неоцененных контекстах на comp.lang.cpp.moderated Даниэль Крюглер излагает три причины:
экстремальное расширение возможно SFINAE случаи:
[…] Причина, по которой они были исключены, была вызвана именно этим экстремальным расширением случаев sfinae (вы открывали ящик Pandora для компилятора) […]
Во многих случаях это просто бесполезно, поскольку каждая лямбда имеет уникальный тип, приведенный гипотетический пример:
template<typename T, typename U>
void g(T, U, decltype([](T x, T y) { return x + y; }) func);
g(1, 2, [](int x, int y) { return x + y; });
Тип лямбды в объявлении и вызове разные (по определению) и поэтому это не может работать.
Имя искажения также становится проблемой, так как как только вы позволяете лямбда в подписи функции тела лямбда придется также покалечить. Это значит придумать правила, чтобы исказить все возможные заявление, что было бы обременительным по крайней мере для некоторых реализаций.
Других решений пока нет …