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++で汎用的なアルゴリズムを利用したり書いたりするために、ここで述べたことが参考になれば幸いです。
