Когда типы замыканий наконец стали структурными типами?

Когда-то велась долгая дискуссия о том, следует ли считать типы замыканий структурными типами или нет (по сути, определяя, будут ли они подходить как NTTP). Подробный пост об этом, сделанный пользователем dfrib , можно найти здесь.

Первоначальное беспокойство по этому поводу, похоже, выразил Чжихао Юань еще в марте 2022 года. В конечном итоге это стало отчетом о дефектах CWG 2542, который был принят на заседании рабочей группы в июне 2023 года. Предлагаемое решение по этому отчету о дефектах было одобрен, и в нем очень четко указано, что типы затворов не являются конструктивными типами.

Это изменение было отражено во многих версиях рабочего проекта C++, по крайней мере, вплоть до N4971 . Интересующий отрывок указан под [expr.prim.lambda.closure]/3. Это также то, что люди найдут, просматривая запись cppreference о лямбда-выражениях, которая ссылается на отчет о дефектах CWG 2542 внизу страницы.

Однако в более поздней версии рабочего проекта C++ N4981 отрывок [expr.prim.lambda.closure]/3 теперь гласит:

Тип закрытия не является агрегатным типом (9.4.2); это структурный введите (13.2) тогда и только тогда, когда лямбда не имеет лямбда-захвата.

Кажется, это отменяет утвержденное решение об отчете о дефектах CWG 2542. Следует ли теперь считать этот отчет о дефектах устаревшим? И на каком совещании/решении/документе типы закрытия теперь стали структурными типами?

Я считаю это не возвратом, а пересмотром. Они отметили, что в случае отсутствия захвата это является структурным, что очень разумно, и заявили, что в противном случае это не так.

NathanOliver 30.04.2024 15:45

Любопытно: есть ли у вас причина (или вы знаете причину), почему лямбда без захвата не должна быть структурным типом?

Yakk - Adam Nevraumont 30.04.2024 15:49

Что ж, если изменение есть в посттокийском проекте, а не в непосредственно предшествующем, возможно, это что-то связано с токийской встречей?

T.C. 30.04.2024 15:54

Суть CWG2542 заключалась в том, что списки захвата не являются общедоступными участниками и автоматически лишают тип замыкания агрегатного и, следовательно, структурного характера. Но в обсуждении не упоминался частный случай пустого захвата. В N4981 этот дефект устранен, заявив, что пустой список захвата делает тип замыкания пустым и, следовательно, структурным. Это исключение из общего случая — точно так же, как неявное преобразование пустого замыкания захвата в указатели функций. Одним из мотивирующих примеров может быть unique_ptr с немедленным встроенным определением удаления.

Red.Wave 30.04.2024 16:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
6
155
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

И на каком совещании/решении/документе типы закрытия теперь стали структурными типами?

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

Это видно из CWG2845:

Сделайте тип закрытия лямбды без захвата структурным типом.

В выпуске 2542 (утвержденном в июне 2023 г.) все типы замыканий не являются структурными типами, т. е. непригодными для использования в качестве параметров шаблона, не являющихся типами. Это приводит к несогласованности обработки преобразования указателя в функцию для типов замыкания без захватов:

Предлагаемая резолюция (одобрена CWG 2024-02-02):

Изменить пункт 3 7.5.5.2 [expr.prim.lambda.closure] следующим образом:

  • Тип замыкания не является агрегатным типом (9.4.2 [dcl.init.aggr]) и не ; это структурный тип (13.2 [temp.param]) тогда и только тогда, когда лямбда-выражение не имеет лямбда-захвата. Реализация может определять тип замыкания иначе, чем...

История здесь была довольно странной.

CWG 2542 — это вопрос, отправленный Чжихао Юанем, который задается вопросом о достоверности этого примера:

template <auto V>
void foo() {}

void bar() {
  foo<[i = 3] { return i; }>();
}

Поскольку правила для структурных типов требуют, чтобы все открытые члены, а члены данных лямбды не были названы и не указаны, поэтому неясно, являются ли они общедоступными или нет.

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

Итак, я представил CWG 2845, опираясь на пример Чжихао, указав, что:

template <auto V>
void foo() {}

void bar() {
  foo<[i = 3] { return i; }>();   // #1: error
  foo<[]{}>();                    // #2: error
  foo<+[]{}>();                   // #3: OK, a function pointer is a structural type
}

Затем было решено считать лямбды без захвата структурными.

Этот последний вопрос был принят на встрече в Токио в марте 2024 года (отсюда и взята текущая формулировка, цитируемая в ФП), что можно рассматривать как отмену/исправление неправильного решения первого вопроса.

Я понимаю, почему стандарт не хочет быть слишком конкретным, когда речь идет о деталях реализации типов замыканий. И, следовательно, определение захватывающих лямбда-выражений не как структурных типов. Однако я не совсем понимаю, почему приведенный вами пример является таким убедительным контраргументом. Поскольку указатели на функции уже соответствуют требованиям структурных типов, а лямбда-выражения без захвата уже предоставляют простой способ их преобразования в таковые. Зачем заморачиваться с изменением правил, чтобы конкретно определить лямбды без захвата как структурные типы? --

303 01.05.2024 13:40

-- Довольно тонкое, но существенное различие между #2 и #3 состоит в том, что каждый вызов #2 приводит к созданию нового экземпляра шаблона foo. Но какую именно выгоду это дает?

303 01.05.2024 13:40

@303 Зачем беспокоиться о разрешении использования лямбда-выражений в качестве параметров шаблона, не относящихся к типу? Поскольку это очевидно полезно (и требовать преобразования в указатель на функцию для достижения этой цели глупо и бессмысленно ограничивает), общие лямбда-выражения не могут быть преобразованы в указатель на функцию, как этот.

Barry 01.05.2024 16:32

@303 Причина Я изначально поднял эту проблему в 2020 году заключается в том, что если лямбда-выражения разрешено использовать в качестве параметра шаблона, не являющегося типом, то это открывает еще одну банку червя для метапрограммирования с сохранением состояния, что еще предстоит официально решенная тема возникла еще в 2015 году через CWG 2118. Хотя внедрение скрытого друга является одновременно хрупким и очень нишевым методом, злоупотребление лямбами в качестве нетиповых параметров шаблона для метапрограммирования с сохранением состояния не так уж и надуманно.

dfrib 06.05.2024 16:00

... Меня немного беспокоит возможность непреднамеренного злоупотребления метапрограммированием с сохранением состояния, которое становится все более широко распространенным из-за этого нового «инструмента» (Закон Хайрама , в некотором смысле), кое-что Я подчеркнул в последующих вопросах и ответах.

dfrib 06.05.2024 16:06

@dfrib Думаю, в целом меня меньше беспокоит «потенциал непреднамеренного злоупотребления метапрограммированием с сохранением состояния», чем «потенциал целевого использования простой передачи функций обычными способами»

Barry 06.05.2024 17:26

@dfrib "... если лямбда-выражения разрешено использовать в качестве параметра шаблона, не являющегося типом, то это открывает еще одну банку червя для метапрограммирования с сохранением состояния..." Например, безопасная проверка полноты типа, для пример? Однако не разрешение лямбда-выражений в качестве NTTP открывает эту банку с червями, а скорее разрешение лямбда-выражений в неоцененных контекстах. Потому что даже если типы замыканий определены как не структурные типы, все равно остается возможность просто сделать: template<typename = decltype([]{})>

303 06.05.2024 18:28

Другие вопросы по теме