【问题标题】:Lambda capture causes incompatible operand types error?Lambda 捕获导致不兼容的操作数类型错误?
【发布时间】:2012-07-09 12:54:26
【问题描述】:

考虑以下代码:

main()
{
    bool t;
    ...
    std::function<bool (bool)> f = t ? [](bool b) { return b; } : [](bool b) { return !b; }; // OK
    std::function<bool (bool)> f = t ? [t](bool b) { return t == b; } : [t](bool b) { return t != b; }; // error
}

使用 Clang 3.1 编译时,非捕获 lambda 的分配有效,而具有捕获的 lambda 分配失败:

main.cpp:12:36: error: incompatible operand types ('<lambda at main.cpp:12:38>' and '<lambda at main.cpp:12:71>')
        std::function<bool (bool)> f2 = t ? [t](bool b) { return t == b; } : [t](bool b) { return t != b; }; // error
                                          ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

为什么捕获相同的变量会导致 2 个 lambda 的类型不兼容?

【问题讨论】:

    标签: c++ lambda c++11 clang


    【解决方案1】:

    lambda 的类型是“唯一的、非联合类类型”,称为闭包类型。每个 lambda 都实现为不同的类型,在声明范围内是局部的,它有一个重载的运算符 () 来调用函数体。

    示例:如果你这样写:

    auto a=[t](bool b){return t==b;};
    auto b=[t](bool b){return t!=b;};
    

    然后编译器编译这个(或多或少):

    class unique_lambda_name_1 
    {
     bool t; 
    public:
     unique_lambda_name_1(bool t_) t(_t) {}
     bool operator () (bool b) const { return t==b; }
    } a(t); 
    class unique_lambda_name_2
    {
     bool t;
    public: 
     unique_lambda_name_2(bool t_) t(_t) {}
     bool operator () (bool b) const { return t!=b; }
    } b(t); 
    

    a 和 b 的类型不同,不能在 ?: 运算符中使用。

    但是,§5.1.2(6) 说,没有捕获的 lambda 的闭包类型有一个非显式的公共转换运算符,它将 lambda 转换为函数指针 - 非闭包可以实现为简单的功能。任何具有相同参数和返回类型的 lambda 都可以转换为相同类型的指针,因此可以将三元 ?: 运算符应用于它们。

    示例:非捕获 lambda:

    auto c=[](bool b){return b;};
    

    是这样实现的:

    class unique_lambda_name_3
    {
     static bool body(bool b) { return b; }
     public:
     bool operator () (bool b) const { return body(b); }
     operator decltype(&body) () const { return &body; }
    } c; 
    

    表示这一行:

    auto x = t?[](bool b){return b;}:[](bool b){return !b;};
    

    实际上是这个意思:

    // a typedef to make this more readable
    typedef bool (*pfun_t)(bool); 
    pfun_t x = t?((pfun_t)[](bool b){return b;}):(pfun_t)([](bool b){return !b;});
    

    【讨论】:

    • 感谢您的详细解释。我不知道它们的实施方式不同。现在说得通了。
    猜你喜欢
    • 2011-11-05
    • 1970-01-01
    • 1970-01-01
    • 2020-06-02
    • 2021-05-20
    • 2018-05-07
    • 2021-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多