Почему лямбда-выражения не допускаются в неоцененных операндах, но допускаются в неоцененных частях константных выражений?

Если мы посмотрим на проект стандарта 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?

13

Решение

Основная причина неоцененные операнды исключение кроется в Стандартные отчеты о дефектах основного языка C ++ и принятые проблемы # 1607. Лямбды в параметрах шаблона который стремится уточнить это ограничение и заявляет о намерении ограничения в разделе 5.1.2 было:

[…] предотвращение необходимости иметь дело с ними в сигнатурах шаблонов функций […]

Поскольку документация выпуска, текущая формулировка фактически имеет дыру, так как константные выражения позволяет им в неоцененном контексте. Но это не дает прямого объяснения этому ограничению. Желание избежать искажения имени выделяется, и вы можете сделать вывод, что избегая расширения SFINAE было также желательно, поскольку предлагаемая резолюция направлена ​​на ужесточение ограничения, хотя несколько жизнеспособных альтернатив SFINAE. Модифицированная версия 5.1.2 параграф 2 следующее:

Лямбда-выражение не должно появляться в неоцененном операнде (пункт 5 [expr]), в аргументе шаблона, в объявлении псевдонима, в объявлении typedef или в объявлении функции или шаблона функции вне тела функции и аргументов по умолчанию [Примечание: цель состоит в том, чтобы не допустить появления лямбда-символов в сигнатуре — конец нота]. [Примечание: закрывающий объект ведет себя как функциональный объект (20.10 [function.objects]). —Конечная записка]

Это предложение было принято и находится в N3936(см этот ответ для ссылки)

Для более ясного обсуждения обоснования, чтобы избежать использования лямбд в качестве неоцененный операнд. Обсуждение под названием Обоснование лямбда-выражений не допускается в неоцененных контекстах на comp.lang.cpp.moderated Даниэль Крюглер излагает три причины:

  1. экстремальное расширение возможно SFINAE случаи:

    […] Причина, по которой они были исключены, была вызвана именно этим экстремальным расширением случаев sfinae (вы открывали ящик Pandora для компилятора) […]
  2. Во многих случаях это просто бесполезно, поскольку каждая лямбда имеет уникальный тип, приведенный гипотетический пример:

    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; });
    

    Тип лямбды в объявлении и вызове разные (по определению) и поэтому это не может работать.

  3. Имя искажения также становится проблемой, так как как только вы позволяете лямбда в подписи функции тела лямбда придется также покалечить. Это значит придумать правила, чтобы исказить все возможные заявление, что было бы обременительным по крайней мере для некоторых реализаций.

16

Другие решения

Других решений пока нет …