代码之家  ›  专栏  ›  技术社区  ›  W.F.

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

  •  6
  • W.F.  · 技术社区  · 7 年前

    隐藏在分解变量中的lambda捕获数。这只是一个理论问题,因为我没有找到任何涵盖捕获成员变量访问修饰符的标准部分。

    int main() {
        int a;
        auto [x] = [a]{};
        static_cast<void>(a);
        static_cast<void>(x);
        return 0;
    }
    

    标准参考

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

    2 回复  |  直到 7 年前
        1
  •  5
  •   Barry    7 年前

    我要说的是,这在标准中没有具体说明,但肯定是不起作用的。关于lambda结构,我们知道的是,从[expr.prim.lambda.closure]:

    lambda表达式的类型(也是闭包对象的类型)是唯一的、未命名的非并集类类型

    闭包类型不是聚合类型

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

    以及:

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

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

    由于非静态数据成员的访问是未指定的,因此可以使用一致性实现将其全部公开,这将满足结构化绑定的情况3。但这在很大程度上违背了lambda的结构方式和结构化绑定应该如何工作的意图,因此如果有任何实现故意这样做,我会感到惊讶。例如gcc, explicitly patched 不允许它。

        2
  •  2
  •   Language Lawyer    5 年前

    为什么不能使用结构化绑定分解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