Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C++ 11 - Why can't we assign a block to a lambda?

So, I just upgraded to Xcode 4.4, and I noticed in the changelog:

Apple LLVM compiler supports additional C++11 features, including lambdas

Which is awesome! So I got around to coding, and I found a few things out:

  1. Lambdas are assignable to Objective-C blocks:

    void (^block)() = []() -> void { 
        NSLog(@"Inside Lambda called as block!");
    };
    
    block();
    
  2. std::function can hold an Objective-C block:

    std::function<void(void)> func = ^{
        NSLog(@"Block inside std::function");
    };
    
    func();
    
  3. We cant assign an Objective-C block to a lambda:

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

Why is this? Shouldn't the two be semantically equivalent, given what we've seen above?

like image 850
Richard J. Ross III Avatar asked Jul 26 '12 12:07

Richard J. Ross III


1 Answers

C++11's lambda's copy-assignment operator is explicitly disabled1. This is not a matter of "semantically equivalent". It can't even assign back to itself. Not to mention an unrelated type.

#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 can hold an Objective-C block.

  • std::function can hold any types which can be invoked as f(a,b,c,...). Since blocks support "the invoke operator", it can also be held by a std::function. But notice that Objective-C and C++ follow different memory management scheme, so storing a block in a std::function for a long time may cause dangling reference.

Lambdas are assignable to Objective-C blocks:

  • Blame SAHChandler2 :). It's not documented yet, though.

1: C++11 §5.1.2/19:

The closure type associated with a lambda-expression has a deleted (8.4.3) default constructor and a deleted copy assignment operator.

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

like image 184
kennytm Avatar answered Oct 02 '22 18:10

kennytm