dfr*_*fri 33 c++ lambda templates language-lawyer c++20
以下所有标准参考均指N4861(2020 年 3 月布拉格后工作草案/C++20 DIS)。
在问答中 无捕获的 lambda 是结构类型吗?很明显,某些 lambda 表达式具有关联的闭包类型,这些闭包类型是(文字和)结构类型,因此特定的此类闭包类型可以用作非类型模板参数;本质上将结构类型 lambda 作为非类型模板参数传递。
Run Code Online (Sandbox Code Playgroud)template<auto v> constexpr auto identity_v = v; constexpr auto l1 = [](){}; constexpr auto l2 = identity_v<l1>;
现在,根据[expr.prim.lambda.closure]/1 ,每个 lambda 表达式的类型都是唯一的
[...] 一个独特的、未命名的非联合类类型,称为闭包类型[...]
另一方面,[basic.def.odr]/1 [extract,强调我的]指出
任何翻译单元不得包含任何变量、函数、类类型、枚举类型、模板、参数的默认参数(对于给定范围内的函数)或默认模板参数的多个定义。
可以说,默认模板参数被认为是需要尊重 ODR 的定义。
...这引出了我的问题:
(如果接近非法,也请强调:例如,如果超出单个实例化的任何事情都会导致 ODR 违规)。
如果这实际上是合法的,则每次调用带有 lambda 作为默认参数的变量模板都会导致唯一特化的实例化:
template<auto l = [](){}>
// ^^^^^^ - lambda-expression as default argument
constexpr auto default_lambda = l;
static_assert(!std::is_same_v<
decltype(default_lambda<>),
decltype(default_lambda<>)>);
Run Code Online (Sandbox Code Playgroud)
如果编译器接受这个例子是正确的,这意味着允许另一种机制来捕获和检索元编程状态,根据CWG 公开问题 2118长期以来一直被认为是一种技术,如
... 神秘的,应该是畸形的。
不,它不是合法的默认非类型模板参数,因为根据CWG 2542的决议,lambda 的闭包类型不是结构类型。
2542. 闭包类型是结构类型吗?
考虑:
Run Code Online (Sandbox Code Playgroud)template <auto V> void foo() {} void bar() { foo<[i = 3] { return i; }>(); }目前尚不清楚闭包类型的数据成员是公共的还是私有的。这很重要,因为它会影响闭包类型是否是结构类型 [...]
[...]
拟议决议(经 CWG 2023-03-30 批准):
7.5.5.2 [expr.prim.lambda.closure] 第 2 段的更改如下:
...闭包类型不是聚合类型(9.4.2 [dcl.init.aggr]),也不是结构类型(13.2 [temp.param])。...