2013/09/25

Objective-C++でBlocksの代わりにC++11のlambdaを利用する

Clang Language Extensionsによると、C++11のlambda式からBlocksポインタへの変換が自動で行われるみたいなので試してみました。

なお、確認にあたって利用したXcodeのバージョンは5.0 (5A1412)です。

簡単な例

拡張子を.mmにしておけば、lambdaで次のように書くことができます。

auto cmptr = [](id x, id y) -> NSComparisonResult { return [x compare:y]; };
auto array = @[ @"spam", @"foo", @"bar", @"bazz" ];
auto sorted = [array sortedArrayUsingComparator:cmptr];
NSLog(@"%@", [sorted componentsJoinedByString:@", "]);
//=> bar, bazz, foo, spam

なお、内部的にはこのlambdaから該当シグネチャのBlockへの変換演算子 (返されるBlockオブジェクトはlambdaへの転送だけを行う) を使うことで実現しているようです。

詳細はClang Language Extensionsの「Interoperability with C++11 lambdas」を参照ください。

複雑な例

もう少し複雑な例として、以前の記事「Objective-C上でブロックオブジェクトによる高階関数を用いてソートする方法について」と同じコードをlambdaで書き直してみました。

auto compByName = [](File* a, File* b) { return [a.name compare:b.name]; };
auto compByIName = [](File* a, File* b) { return [a.name caseInsensitiveCompare:b.name]; };
auto makeCompByDir = [](NSComparator f) {
    return [f](File* a, File* b) {
        BOOL adir = a.isDirectory;
        BOOL bdir = b.isDirectory;
        if (a.isDirectory == b.isDirectory) return f(a, b);
        return (adir && ! bdir)? NSOrderedAscending : NSOrderedDescending;
    };
};
auto makeCompByKind = [](NSComparator f) {
    return [f](File* a, File* b) -> NSComparisonResult {
        NSComparisonResult res = [a.name.pathExtension
                                  caseInsensitiveCompare:b.name.pathExtension];
        return res == NSOrderedSame? f(a, b) : res;
    };
};

auto sorted = [array sortedArrayUsingComparator:makeCompByDir(makeCompByKind(compByName))];

以前の記事がARC未対応であったりしますが、上のコードと比べてもあまり代わりませんね。

ちょっと違うのは、autoを利用していることと、fを明示的にキャプチャしていることくらいでしょうか。

なお、Objective-C++にするとautoでBlocksの宣言が省略できるようになるので、個人的にはそれだけでもとても嬉しかったりします。

auto compByName = ^(id a, id b) {
    return [[a name] compare:[b name]];
};

関連リンク

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。