Objective-C++ 11-Почему мы не можем назначить блок лямбде?
Итак, я только что обновился до Xcode 4.4, и я заметил в списке изменений:
Компилятор Apple LLVM поддерживает дополнительные функции C++11, включая лямбды
Это потрясающе! Итак, я занялся кодированием и обнаружил несколько вещей:
-
Лямбды присваиваются блокам 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 блоку A лямбда:
auto lambda = []() -> { NSLog(@"Lambda!"); }; lambda = ^{ // error! NSLog(@"Block!"); }; lambda();
Почему это? Разве они не должны быть семантически эквивалентны, учитывая то, что мы видели выше?
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:
- Вина Сахчандлер2 :). Но это еще не задокументировано.
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
это оболочка, которая предназначена для хранения любого вызываемого типа; вы должны использовать ее для хранения вызываемых объектов, которые могут быть разных типов.