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

Если мы посмотрим на черновик стандарта 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) не очень полезны, поскольку каждая лямбда имеет уникальный тип. Хотя неясно, почему мы хотели бы разрешить их в неоцененном контексте константного выражения, возможно, чтобы разрешить СФИНАЕ?


person Shafik Yaghmour    schedule 06.03.2014    source источник


Ответы (1)


Основная причина исключения неоцененных операндов описана в Отчеты о дефектах стандартного основного языка C ++ и принятые проблемы №1607. Lambdas в параметрах шаблона, который пытается прояснить это ограничение и заявляет, что цель ограничения в разделе 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 для компилятора) [...]

  1. Во многих случаях это просто бесполезно, поскольку каждая лямбда имеет уникальный тип, приведенный гипотетический пример:

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

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

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

person Shafik Yaghmour    schedule 06.03.2014
comment
n3936 вроде был защищен паролем (fdis?), ссылки тоже битые. - person dyp; 07.03.2014
comment
@dyp хммм, это сработало сегодня утром, да ладно. Локи также связался с этим здесь, так что это может быть временным, позвольте мне посмотреть, смогу ли я выяснить, что происходит. - person Shafik Yaghmour; 07.03.2014
comment
(Я думаю, что сейчас это FDIS. Новая ссылка на open-std.org/jtc1/sc22/wg21/docs/papers/2014 предлагает это: open-std.org/jtc1/sc22/wg21/prot/14882fdis/n3936.pdf) - person dyp; 07.03.2014
comment
См. Также D0315R2. - person Shafik Yaghmour; 30.04.2017
comment
Похоже, что p0315r3 был принят для C ++ 20 - person Shafik Yaghmour; 12.11.2017