8. ラムダ式を使った汎用的なアルゴリズムの適用
前節では、関数オブジェクトを作ることにより、Run関数内の環境を汎用アルゴリズムであるAppendIf関数とForEach関数に渡すことができました。
しかし、関数オブジェクトを作るためには、一々クラスを用意する必要があります。面倒ですし、プログラムが複雑になります。
ここまでしないと、汎用的なアルゴリズムを使えないのでしょうか?
ラムダ式
そこでC++11から追加されたラムダ式です。簡潔な記述でクロージャーを実現することができます。
C++のラムダ式については、次のページを参照してください。
- 『C++0xの新機能「ラムダ式」を次期Visual Studioでいち早く試す』(CodeZine)
書籍のリストの中から、タイトルか出版社名に "リ" を含むものをコンソールに表示(ラムダ式版)
では、先のプログラムをラムダ式を使って書いてみましょう。関数オブジェクトと異なり、クラスを作る必要がない分ぐっとシンプルです。
#include <iostream> #include <list> #include <vector> #include <string> using namespace std; #include "Book.h" #include "Publisher.h" #include "MyCollection.h" using namespace MyCollection; class Program { public: void Run() { const vector<Publisher> publisherList = { Publisher(L"技術評論社" ), Publisher(L"翔泳社" ), Publisher(L"オライリー・ジャパン"), Publisher(L"SBクリエイティブ" ) }; const list<Book> bookList = { Book(L"4774157155", L"C++ ポケットリファレンス" , 0), Book(L"4798108936", L"C++ の絵本" , 1), Book(L"4798119768", L"独習 C++ 第4版" , 1), Book(L"4873110637", L"C++ プログラミング入門" , 2), Book(L"4797376686", L"C++ テンプレートテクニック 第2版", 3) }; const wstring searchWord = L"リ"; list<Book> filteredBookList; AppendIf( bookList, filteredBookList, // ラムダ式 (searchWord を値でキャプチャ、publisherList を参照でキャプチャ) // -> の前の const Book& book が入力で後が bool 型の出力 [searchWord, &publisherList](const Book& book) -> bool { return book.GetTitle().find(searchWord) != wstring::npos || publisherList[book.GetPublisherIndex()].GetName() .find(searchWord) != wstring::npos; } ); ForEach( filteredBookList, // ラムダ式 (publisherList を参照でキャプチャ) // -> の前の const Book& book が入力で後が実行内容 [&publisherList](const Book& book) -> void { wcout << L"コード: " << book.GetCode () << L", タイトル: " << book.GetTitle() << L", 出版社: " << publisherList[book.GetPublisherIndex()].GetName() << endl; } ); } }; int main() { wcout.imbue(locale("Japanese", locale::ctype)); Program().Run(); return 0; }
実行結果は、元々のプログラムと同じです。
コード: 4774157155, タイトル: C++ ポケットリファレンス, 出版社: 技術評論社 コード: 4873110637, タイトル: C++ プログラミング入門, 出版社: オライリー・ジャパン コード: 4797376686, タイトル: C++ テンプレートテクニック 第2版, 出版社: SBクリエイティブ
ラムダ式を使うことで、余計な記述(本来のプログラムのロジックでない部分)が減り、簡潔な記述となりました。
9. まとめ
C++における汎用的なアルゴリズムの分離について考察しました。
汎用的なアルゴリズムがどのように分離されると良いか、そして分離されたアルゴリズムがどのように使われると良いか、を述べました。
今回は汎用的なアルゴリズムを自作しましたが、このようなアルゴリズムはC++のライブラリの中に既にたくさん存在し、同様に使うことができます。
例えば、次のページでは<algorithm>ヘッダーなどに含まれるアルゴリズムが紹介されています。
- 『「ソートも、サーチも、あるんだよ」~標準C++ライブラリにみるアルゴリズムの面白さ <algorithm>のソートたち』(CodeZine)
- 『Visual C++ 2010に追加されたSTLアルゴリズム ── Visual C++ バージョン10で拡充された関数群』(CodeZine)
ラムダ式を活用すれば、簡潔な記述で、これらの既存のアルゴリズムを使うことができます。
C++で汎用的なアルゴリズムを利用したり書いたりするために、ここで述べたことが参考になれば幸いです。