[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) 结构类型 ...
structural type 的规则是:--我的重点--
(7.1) 标量类型,或
(7.2) 左值引用类型,或
(7.3) 具有以下属性的文字类类型:
(7.3.1) 所有基类和非静态数据成员都是public和non-mutable和
(7.3.2) 所有基类和非静态数据成员的类型都是结构类型或其(可能是多维的)数组。
由于 lambda 没有基类,唯一的要求是它必须是 literal class type ([basic.types]),其中包括:
(10.5.2) ... 闭包类型 ([expr.prim.lambda.closure]) ...
结构类型的数据成员也应该是结构类型,这适用于这种情况下的 lambda 捕获,只要它的所有成员都是 public 和 不可变。
@Nicol Bolas commented below 即使constexpr 文字类型捕获,标准也没有强制要求将捕获作为公共字段进行管理。
底线是,在 C++20 中,没有捕获的 constexpr lambda 表达式作为模板非类型参数是合法的(基于上面提到的[basic.types]/10.5.2)。
另见an answer by @Barry to a similar question。
下面的代码compiles with gcc,但据我了解,Nicol Bolas 的评论,并非所有情况都由规范保证(或者更糟糕的是,所有情况都不受规范保证)规格?)。
假设我们有:
template <auto T> struct A {};
struct B {};
struct C {
~C(){}
};
文字类型 lambda,应该是合法的作为模板参数:
// 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;
Lambdas,由 gcc 作为模板参数编译,但正如 Nicol Bolas 在评论中所说 - 规范不保证它们是文字类型:
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;
非文字类型 lambda,不合法 作为模板参数:
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;