[temp.arg.nontype] / 1:
Если тип T параметра шаблона содержит тип-заполнитель ([dcl.spec.auto]) или заполнитель для выведенного типа класса ([dcl.type.class.deduct]), типом параметра является тип выводится для переменной x в придуманном объявлении
T x = template-argument ;
Если выведенный тип параметра не разрешен для объявления параметра шаблона ([temp.param]), программа имеет неправильный формат.
Итак, правила устанавливаются [temp.param] / 6:
Параметр шаблона без типа должен иметь один из следующих типов (возможно, квалифицированных cv): ...
(6.1) структурный тип ...
Правила для структурного типа: - -Мой курсив -
(7.1) скалярный тип, или
(7.2) ссылочный тип lvalue, или
(7.3) тип буквального класса со следующими свойствами:
(7.3.1) все базовые классы и нестатические элементы данных являются общедоступными и неизменяемыми и
(7.3.2) типы всех базовых классов и нестатических элементов данных являются структурными типами или (возможно, многомерными) их массивами.
Поскольку у лямбда нет базового класса, единственное требование - он должен быть литералом тип класса ([basic.types]), который включает:
(10.5.2) ... тип закрытия ([ expr.prim.lambda.closure]) ...
Члены данных структурного типа также должны быть структурного типа, в данном случае это относится к захвату лямбда-выражения, если все его члены являются общедоступными и < em> неизменяемый.
@Nicol Bolas прокомментировал ниже, что лямбда с захватами, даже если захватывает тип литерала constexpr, стандарт не требует управления захватами как общедоступными полями.
Суть в том, что в C ++ 20 лямбда-выражение constexpr без захвата должно быть разрешено в качестве аргумента без типа шаблона (на основе [basic.types] /10.5.2, упомянутых выше).
См. Также ответ @Barry на аналогичный вопрос.
Код ниже компилируется с помощью gcc, но, как я понимаю из комментария Николаса Боласа em >, не все случаи гарантированы спецификацией (или, что еще хуже, все случаи не гарантированы спецификацией?).
Предположим, у нас есть:
template <auto T> struct A {};
struct B {};
struct C {
~C(){}
};
Лямбды буквального типа, разрешенные в качестве аргументов шаблона:
// compiles in gcc and should be ok by the spec as of [basic.types]/10.5.2
A<[](){}> a; // compiler deduces the anonymous lambda to be constexpr
auto lmb1 = [](){};
// same as above
A<lmb1> a1;
// compiler deduces lmb1 above to be constexpr
// same as it will deduce the following:
B b {};
A<b> here_i_am;
Лямбды, которые скомпилированы gcc в качестве аргументов шаблона, но, как утверждает в комментарии Никол Болас, спецификация не гарантирует, что они будут буквальными типами:
const int i = 0;
constexpr auto lmb2 = [i](){};
// compiles in gcc but is not guaranteed by the spec
A<lmb2> a2;
constexpr auto lmb3 = [b](){}; // B is literal
// compiles in gcc but is not guaranteed by the spec
A<lmb3> a3;
Лямбды нелитерального типа, недопустимые в качестве аргументов шаблона:
const int j = 0;
// below doesn't compile: <lambda()>{j} is not a constant expression
constexpr auto lmb4 = [&j](){}; // local reference - not constexpr
A<lmb4> a4;
C c;
// below doesn't compile: <lambda()>'{c} does not have 'constexpr' destructor
constexpr auto lmb5 = [c](){}; // C is not literal
A<lmb5> a5;
person
Amir Kirsh
schedule
11.06.2020
constexpr auto= ...
. А как насчет других компиляторов? Толькоconstexpr
s могут быть параметрами шаблона (включаяauto
). - person Sam Varshavchik   schedule 11.06.2020