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


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

Компилятор Apple LLVM поддерживает дополнительные функции C++11, включая лямбды

Это потрясающе! Итак, я занялся кодированием и обнаружил несколько вещей:

  1. Лямбды присваиваются блокам 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 блоку A лямбда:

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

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

2 14

2 ответа:

Оператор копирования-присваивания лямбды C++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,...). Поскольку блоки поддерживают "оператор invoke", он также может быть удержан std::function. Но обратите внимание, что Objective-C и C++ следуют разным схемам управления памятью, таким образом, хранение блока в std::function в течение длительного времени может привести к оборванной ссылке.

Лямбды присваиваются блокам Objective-C:


1: С++11 §5.1.2/19:

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

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

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

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

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