Все стандартные ссылки ниже, если явно не указано иное, относятся к N4861 (март 2020 г. послепражский рабочий проект / C ++ 20 DIS).
Типом лямбда-выражения без захвата (его типом замыкания) является структурный тип.
В дальнейшем мы будем называть тип лямбды исключительно типом замыкания.
Как показано в стандартных отрывках ниже, тип закрытия лямбды без захвата:
- удовлетворяет требованиям, чтобы он был литеральным (классом) типом, и более того
- выполняет требования к литеральному типу, чтобы он был структурным типом,
и, таким образом, может использоваться как тип для параметра шаблона, не являющегося типом, например, фрагмент примера
template<auto v>
constexpr auto identity_v = v;
constexpr auto l1 = [](){};
constexpr auto l2 = identity_v<l1>;
действительно хорошо сформирован.
Тип закрытия лямбды - это тип класса без объединения
Как регулируется [expr.prim.lambda.closure] / 1 [выделено мое]
Тип лямбда-выражения (который также является типом закрывающего объекта) является уникальным безымянным типом класса без объединения, называемым закрывающим типом, свойства которого описаны ниже.
тип замыкания - это тип класса без объединения.
Тип закрытия лямбда-выражения без захвата - это литерал (класс).
Как регулируется [basic.types] / 10 [извлечение, акцент мой]
Тип является буквальным типом, если он:
- [...]
- a possibly cv-qualified class type that has all of the following properties:
- it has a constexpr destructor ([dcl.constexpr]),
- это либо тип закрытия ([expr.prim.lambda.closure]), либо агрегированный тип ([dcl.init.aggr]), либо имеет хотя бы один constexpr конструктор или шаблон конструктора (возможно, унаследованный от базового класса), который не является конструктором копирования или перемещения,
- если это объединение, по крайней мере, один из его нестатических элементов данных имеет энергонезависимый литеральный тип, и
- если это не объединение, все его нестатические элементы данных и базовые классы имеют энергонезависимые литеральные типы.
тип закрытия является буквальным типом, если
- имеет деструктор constexpr, и если
- все его нестатические элементы данных относятся к энергонезависимым литеральным типам.
Тип закрытия лямбда-выражения без захвата не имеет нестатических элементов данных, поэтому последнее требование выполняется. А что насчет первого, деструктора constexpr?
Неявно сгенерированный деструктор constexpr
Как регулируется [expr.prim.lambda.closure] / 14
Тип закрытия, связанный с лямбда-выражением, имеет неявно объявленный деструктор ([class.dtor]).
деструктор типа закрытия объявляется неявно. Кроме того, [/dcl.fct.def.default sizes] 5 описывает [отрывок, выделено мое]
Функции с явно заданными по умолчанию и неявно объявленные функции вместе называются функциями по умолчанию, и реализация должна предоставлять для них неявные определения ([class.ctor ], [class.dtor], [class.copy.ctor], [class.copy.assign]), [...]
что собирательный термин дефолтные функции также включают неявно объявленные деструкторы.
Наконец, [class.dtor] / 9
Деструктор по умолчанию является деструктором constexpr, если он удовлетворяет требованиям для деструктора constexpr ([dcl.constexpr]).
описывают, что деструкторы по умолчанию являются деструкторами constexpr, если они соответствуют требованиям [dcl.constexpr], особенно [dcl.constexpr] / 3 и [dcl.constexpr] / 5 [выдержки, акцент мой]
[dcl.constexpr] / 3 Определение функции constexpr должно удовлетворять следующим требованиям:
- [...]
- если функция является конструктором или деструктором, ее класс не должен иметь никаких виртуальных базовых классов;
- [...]
[dcl.constexpr] / 5 Определение деструктора constexpr, function-body которого не является = delete
, должно дополнительно удовлетворять следующему требованию:
- для каждого подобъекта типа класса или его (возможно, многомерного) массива этот тип класса должен иметь деструктор constexpr.
все это выполняется для типа закрытия лямбда-выражения без захвата (без базовых классов и без подобъектов; см. [intro.object] / 2 для последнего).
Таким образом, тип закрытия лямбды без захвата является буквальным типом.
Тип закрытия лямбды без захвата является структурным типом
Согласно [temp.param] / 6 и [temp.param] / 7 [выдержка, выделение сильный> мой]
[temp.param] / 6 Параметр шаблона, не являющийся типом, должен иметь один из следующих (возможно, квалифицированных cv) типов:
- структурный тип (см. ниже),
- [...]
[temp.param] / 7
Структурный тип может быть одним из следующих:
- скалярный тип, или
- ссылочный тип lvalue, или
- a literal class type with the following properties:
- all base classes and non-static data members are public and non-mutable and
- типы всех базовых классов и нестатических элементов данных являются структурными типами или (возможно, многомерными) их массивами.
литеральный тип класса тривиально является структурным типом, если он не имеет базовых классов и нестатических членов данных. Оба эти утверждения справедливы для лямбда без захвата, и, таким образом, тип замыкания лямбда без захвата является структурным типом.
Некоторые примечания об исходном намерении разрешить типу замыкания лямбды быть буквальным типом
N4487 предложил разрешить определенные лямбда-выражения и операции с некоторыми закрывающими объектами, которые должны появляться в константных выражениях, и содержали специальный раздел, посвященный теме закрывающего типа, являющегося буквальным типом:
Замыкающий объект должен быть литеральным типом, если тип каждого из его элементов данных является литеральным типом.
Тип закрытия в C ++ 14 никогда не может быть буквальным типом - даже если все его члены данных являются литеральными типами - потому что в нем отсутствует конструктор constexpr, который не является конструктором копирования или перемещения. Если бы такому типу замыкания было разрешено иметь неявно определенный конструктор по умолчанию, это был бы constexpr, что сделало бы его буквальным типом. Но поскольку типы замыкания по определению должны иметь удаленные конструкторы по умолчанию, реализации запрещено неявно определять их. [...]
P0170R1, содержащий основную формулировку из N4487 был принят и реализован для C ++ 17.
Однако в то время (C ++ 14 и C ++ 17) деструктор не мог быть constexpr, и поэтому, естественно, не существовало требования, чтобы литеральный тип имел деструктор constexpr; [basic.types] /10.5.1 в N4140 (C ++ 14), а также [basic.types] / 10.5.1 в N4659 (C ++ 17) вместо этого требовал, чтобы деструктор был тривиальным:
Тип является буквальным типом, если он:
- [...]
- a class type (Clause [class]) that has all of the following properties:
- it has a trivial destructor,
- [...]
P1907R1, поддерживается для C ++ 20 расширено требование к объектам параметров шаблона, которые должны иметь постоянное уничтожение; [temp.param] / 8 [курсив < / strong> мой]:
id-expression с именованием не относящегося к типу параметра-шаблона типа класса T
обозначает статический объект продолжительности хранения типа const T
, известный как объект параметра шаблона < / em>, значение которого совпадает со значением соответствующего аргумента шаблона после того, как он был преобразован в тип параметра-шаблона. Все такие параметры шаблона в программе одного типа с одинаковым значением обозначают один и тот же объект параметра шаблона. [...] Объект параметра шаблона должен постоянно уничтожаться.
и, P0784R7, также принимается для C ++ 20, в частности, содержал введение уничтожения constexpr, включая обновление требования, чтобы тип был буквальным типом; особенно описано в более ранней версии документа, P0784R1 а>:
Предлагаемые правила для деструкторов constexpr:
- [...]
- Литеральный тип требует деструктора constexpr (ранее требовалось более строгое требование тривиального деструктора)
person
dfrib
schedule
21.10.2020