【问题标题】:Objective-C++ 11 - Why can't we assign a block to a lambda?Objective-C++ 11 - 为什么我们不能将块分配给 lambda?
【发布时间】:2012-07-25 00:56:37
【问题描述】:

所以,我刚刚升级到 Xcode 4.4,我在更新日志中注意到:

Apple LLVM 编译器支持其他 C++11 功能,包括 lambdas

这太棒了!所以我开始编码,我发现了一些东西:

  1. Lambda 可分配给 Objective-C 块:

    void (^block)() = []() -> void { 
        NSLog(@"Inside Lambda called as block!");
    };
    
    block();
    
  2. std::function 可以容纳一个 Objective-C 块:

    std::function<void(void)> func = ^{
        NSLog(@"Block inside std::function");
    };
    
    func();
    
  3. 我们不能将 Objective-C 块分配给 lambda:

    auto lambda = []() -> {
        NSLog(@"Lambda!");
    };
    
    lambda = ^{ // error!
        NSLog(@"Block!");
    };
    
    lambda();
    

这是为什么?鉴于我们在上面看到的,这两者在语义上不应该是等价的吗?

【问题讨论】:

  • +1 好消息,好问题 - 迫不及待想看到更多关于这个主题的信息。

标签: c++ objective-c lambda c++11 objective-c++


【解决方案1】:

C++11 的 lambda 的复制赋值运算符被显式禁用1。这不是“语义等价”的问题。它甚至不能分配回自己。更不用说不相关的类型了。

#include <cstdio>
#include <type_traits>

int main() {
    auto lambda1 = []() -> void { printf("Lambda 1!\n"); };
    lambda1 = lambda1;  // error: use of deleted function ‘main()::<lambda()>& main()::<lambda()>::operator=(const main()::<lambda()>&)’
    return 0;
}

std::function 可以容纳一个 Objective-C 块。

  • std::function 可以保存任何可以作为f(a,b,c,...) 调用的类型。由于块支持“调用运算符”,它也可以由std::function 持有。但请注意,Objective-C 和 C++ 遵循不同的内存管理方案,因此将块长时间存储在 std::function 中可能会导致悬空引用。

Lambda 可分配给 Objective-C 块:

  • 责备SAHChandler2 :)。不过,它尚未记录在案。

1:C++11 §5.1.2/19:

lambda-expression 关联的闭包类型具有已删除的 (8.4.3) 默认构造函数和已删除的复制赋值运算符。

2http://llvm.org/viewvc/llvm-project?view=rev&revision=150620

【讨论】:

    【解决方案2】:

    Lambda 有自己的、实现定义的类型,这些类型特定于每个 lambda。以下代码也是错误:

    auto l1=[](){return 1;}
    auto l2=[](){return 2;}
    l1=l2; //Error
    

    std::function 是一个包装器,旨在保存任何可调用类型;您应该使用它来保存可能是不同类型的可调用对象。

    【讨论】:

    • 另外注意:非捕获 lambdas(如本例中的那些)可以在赋值时隐式转换为函数指针类型——例如using fp_t = std::add_pointer_t&lt;int(void)&gt;; fp_t fp = l1; 在这种情况下可以工作。如果 lambda 被声明为捕获(比如 int x = 42; auto l3 = [&amp;x](){ return x; }),则没有等效的函数指针类型 - 需要一个 std::function 实例来保存捕获 lambda。
    猜你喜欢
    • 2017-07-20
    • 2021-08-03
    • 1970-01-01
    • 2012-11-10
    • 1970-01-01
    • 2015-01-22
    • 2020-07-02
    • 2016-12-22
    相关资源
    最近更新 更多