为什么lambda表达式的捕获列表不能使用结构化绑定进行分解

时间:2017-09-26 08:13:54

标签: c++ lambda language-lawyer c++17 structured-bindings

在你扔烂番茄之前

我知道lambda分解的实际应用目前是有限的 因为人们无法找到替代失败友好的方式来检查 隐藏在分解变量中的lambda捕获数。这只是一个理论问题,因为我未能找到任何涵盖捕获成员变量访问修饰符的标准部分。

示例

SELECT sum(sal) 
FROM emp_table 
WHERE age IN (21, 22) OR
(age = 33 AND exp > 10);

标准参考

关于lambda capture的标准部分很长,所以我可能错过了相关的片段。我注意到的是,强调对应于捕获的非静态成员是/必须是未命名的。

2 个答案:

答案 0 :(得分:5)

我会说标准没有指明这一点,但肯定不起作用。我们对lambda结构的了解是,来自[expr.prim.lambda.closure]:

  

lambda表达式的类型(也是闭包对象的类型)是一个唯一的,未命名的非联合类类型

  

闭包类型不是聚合类型

和,来自[expr.prim.lambda.capture]:

  

对于通过复制捕获的每个实体,在闭包类型中声明一个未命名的非静态数据成员。这些成员的声明顺序未指定。

  

未指定是否在闭包类型中为引用捕获的实体声明了其他未命名的非静态数据成员。如果声明,这些非静态数据成员应为字面型。

拥有未命名成员的目的是避免在lambda体外访问它们。这些成员的后果另外还有未指定的顺序意味着只要您通过副本进行多次捕获,您甚至无法知道结构化绑定的作用。

int a=1, b=2;
auto [x, y] = [a, b]{}; // x==1 or x==2??

通过引用捕获的结果不一定是命名成员意味着您甚至不知道要在结构化绑定声明中列出多少个标识符。

由于未指定非静态数据成员的访问,因此可以使符合的实现将它们全部公开,这将满足结构化绑定的情况3。但这非常违背lambdas的结构方式以及结构化绑定的工作方式,所以如果有任何实现有意识地这样做,我会感到惊讶。例如,gcc explicitly patched禁止它。

答案 1 :(得分:1)

  

为什么不能使用结构化绑定来分解lambda表达式的捕获列表

实际上可以。以下

template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
template<class... Ts> overload(Ts...) -> overload<Ts...>;

int main()
{
    auto f = [x = 1, y = 2]() { return x + y; };
    // auto [a, b] = f; // error: cannot decompose lambda closure type 'main()::<lambda()>'

    overload o { f, };
    auto [a, b] = o;

    return b; // returns 2
}

在GCC中继https://godbolt.org/z/15c90z中工作。