CodeZine(コードジン)

特集ページ一覧

C++0xの新機能「ラムダ式」を次期Visual Studioでいち早く試す

Visual Studio 2010 β1で遊んでみた

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2009/09/10 14:00

目次

もっと手軽に書けないのか!? …ラムダ式

 関数オブジェクトを定義し、そのインスタンスをアルゴリズムの引数に与えることで、ユーザー(プログラマ)の期待する解を得ているわけですが、上記サンプルで定義した関数オブジェクトのキモとなっているのはそれぞれ、

{ return x % n_ == 0; }
{ return ( x > 0 ? x : -x ) < ( y > 0 ? y : -y);}

 わずかにこの部分だけです。たったこれだけのためにcan_divideやらabs_lessやら、classを定義しなければなりません。このわずらわしさを一気に解消してくれるのが、C++0Xで導入されるラムダ式(lambda expression)です。先ほどのサンプルをラムダ式で表現すると、それぞれ次のようになります。

ラムダ式で表現した場合
/*
 * n で割り切れる要素を探す
 */
#include <algorithm>
#include <iostream>

int main() {
  int ar[] = { 9, 7, 5, 3, 1, -2, -4, -6, -8, 0 };
  int n = 4;
  int* found = std::find_if(ar, ar+10,
                            // ↓これがラムダ式
                            [n](int x) { return x % n == 0;} );
  if ( found != ar+10 ) {
    std::cout << n << " で割り切れる数 "
                   << *found << " が見つかりました。" << std::endl;
  }
}

/*
 * 絶対値で昇順にソートする
 */
#include <algorithm>
#include <iostream>

int main() {
  int ar[] = { 9, 7, 5, 3, 1, -2, -4, -6, -8, 0 };
  std::sort(ar, ar+10,
            // ↓これがラムダ式
            [](int x, int y) { return ( x > 0 ? x : -x ) < ( y > 0 ? y : -y); });
  std::for_each(ar, ar+10,
                // ↓これもラムダ式
                [](int x) { std::cout << x << " ";});
}

 いかがですか? あきれるほど簡単になりますね。いずれのサンプルでも、関数オブジェクトの()演算子での処理を、そのままfind_ifsortの引数に書き下しています。従来、わざわざ定義していた関数オブジェクトを直接書き下すことができるのが、ラムダ式の機能です。

ラムダ式の構文

 ラムダ式は以下に示す6つの部分で構成されています。

ラムダ式の構造(※MSDNより引用)
ラムダ式の構造

1:lambda-introducer

 ラムダ式は[]から定義が始まります。[]の中には、キャプチャ宣言を記述します(後述)。

2:lambda-parameter-declaration-list

 ラムダ式に与える引数の並びです。引数のデフォルト値は指定できませんし、可変長パラメータも不可。名前のない引数も許されません。

例1
[](int x = 3) { ... } // error: デフォルト値不可
[](int x, int y , ...) { ... } // error: 可変長パラメータ不可
[](int x, int) { ... } // error: 無名引数不可

3:mutable-specification

 ラムダ内にキャプチャ(後述)された変数の書き換え(代入/変更)を許すとき、「mutable」を指定します。

4:exception-specification

 ラムダ式の中から例外をthrowするとき、「throw(送出される例外の並び)」を記述します。

5:lambda-return-type-clause

 ラムダ式が返す値の型を->の後ろに指定します。ラムダ式の本体が1つのreturn式であるとき、またはラムダ式が値を返さないときは省略可能です。

例2
[](int x) { std::cout << x; } // 省略可: void とみなす
[](int x) { return x*2; } // 省略可: intとみなす

6:compound-statement

 ラムダ式の最後にあるのが、ラムダ式で評価される本体(lambda-body)です。

ラムダ式を変数に

 ラムダ式は関数オブジェクトとして機能し、変数に格納できます。このときの変数の型には、C++0Xで新たに導入された型推論:auto、もしくは標準ライブラリが提供するクラス・テンプレート:functionが使えます。

#include <iostream>
#include <string>
#include <functional>

// Visual C++ では TR1ライブラリが std::tr1 に置かれている。
// std::tr1:: を std:: と略記するための便法。
namespace std { using namespace std::tr1; }

int main() {
  // autoによる
  auto println =
    [](const std::string& str) { std::cout << str << std::endl; };

  // std::function<>による
  std::function<std::string (const std::string&)> polite =
    [](const std::string& str) { return str+"さん"; };

  std::string msg = polite("香田仁"); // politeの評価(呼び出し)
  println(msg); // printlnの評価(呼び出し)
  println(polite("いちにの"));
}

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • επιστημη(エピステーメー)

    C++に首まで浸かったプログラマ。 Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"り わんくま同盟でたまにセッションスピーカやったり 中国茶淹れてにわか茶人を気取ってたり、 あと Facebook とか。 著書: - STL標準...

あなたにオススメ

All contents copyright © 2005-2022 Shoeisha Co., Ltd. All rights reserved. ver.1.5