Objective-C ++ 11 - Почему мы не можем назначить блок лямбда?

Итак, я просто обновился до Xcode 4.4, и я заметил в сводке изменений:

Компилятор Apple LLVM поддерживает дополнительные возможности С++ 11, включая lambdas

Это потрясающе! Поэтому я перешел к кодированию, и я нашел несколько вещей:

  • Lambdas можно назначить блокам Objective-C:

    void (^block)() = []() -> void { 
        NSLog(@"Inside Lambda called as block!");
    };
    
    block();
    
  • std::function может содержать блок Objective-C:

    std::function<void(void)> func = ^{
        NSLog(@"Block inside std::function");
    };
    
    func();
    
  • Мы не можем назначить блок Objective-C для лямбда:

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

Почему это? Разве два семантически не эквивалентны, учитывая то, что мы видели выше?

Ответы

Ответ 1

Оператор lambda copy-присваивания С++ 11 явно отключен 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 и С++ следуют различным схемам управления памятью, поэтому сохранение блока в std::function в течение длительного времени может вызвать зависание ссылки.

Lambdas можно назначить блокам Objective-C:

  • Обвинение SAHChandler 2:). Однако он еще не задокументирован.

1: С++ 11 §5.1.2/19:

Тип замыкания, связанный с lambda-выражением, имеет удаленный (8.4.3) конструктор по умолчанию и оператор делегирования удаленной копии.

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

Ответ 2

У Lambdas есть свои, определенные реализацией типы, которые являются специфическими для каждой лямбда. Следующий код также является ошибкой:

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

std::function - это оболочка, которая предназначена для хранения любого вызываемого типа; вы должны использовать это для хранения вызывающих вызовов, которые могут быть разных типов.