C#とC++のラムダ式

ラムダ式(lambda expression)とは

  • 要するに名前のない関数 (無名関数、匿名関数)、その場で書く関数 (関数リテラル)
  • 値と同じように変数に代入したり関数に渡したりできる。
  • C#C++では微妙に書き方が違う。
  • C#は (引数) => {処理}
  • C++は [キャプチャ](引数) -> 戻り値 {処理}
  • 正確に言うと、C#ラムダ式delegateを作る糖衣構文だけど、以下では雑な説明をする。

ラムダ式を変数に代入

// C#
Action hoge = () => { Console.WriteLine("Hello, world!"); };
hoge();
// C++
auto hoge = []{ cout << "Hello, world!" << endl; };
hoge();
  • C#では戻り値のないラムダ式の型はAction
  • C++では型推論でOK
  • C++では引数も戻り値もないとき () -> は省略できる。

ラムダ式を関数に渡す

// C#
static void piyo(Action func)
{
    func();
}
static void Main(string[] args)
{
    piyo(() => { Console.WriteLine("Hello, world!"); });
}
// C++
template <typename Func>
void piyo(Func func)
{
    func();
}
int main(void)
{
    piyo([]{ cout << "Hello, world!" << endl; });
    return 0;
}
  • C++では引数の型はテンプレートを用いる。

ラムダ式に引数を渡す

// C#
Action<string> hoge = (string str) => { Console.WriteLine(str); };
hoge("Hello, world!");
// C++
auto hoge = [](string str){ cout << str << endl; };
hoge("Hello, world!");

ラムダ式から戻り値を返す

// C#
Func<int, int> twice = (int x) => { return 2 * x; };
Console.WriteLine(twice(13));
// C++
// 戻り値の型を明示
auto twice1 = [](int x) -> int { return 2*x; };
cout << twice1(13) << endl;

// 戻り値の型を省略
auto twice2 = [](int x) { return 2*x; }; 
cout << twice2(13) << endl;

キャプチャ(ラムダ式が定義された関数のスコープの変数を取り込む)

// C#
static void piyo(Action func)
{
    func();
}
static void Main(string[] args)
{
    string hello = "Hello, world!";
    Action hoge = () => { Console.WriteLine(hello); };
    piyo(hoge);
}
// C++
template <typename Func>
void piyo(Func func)
{
    func();
}
int main(void)
{
    string hello = "Hello, world!";
    auto hoge1 = [&] { cout << hello << endl; }; //参照
    auto hoge2 = [=] { cout << hello << endl; }; //コピー
    auto hoge3 = [ ] { cout << hello << endl; }; //エラーになる
    piyo(hoge1);
    piyo(hoge2);
    return 0;
}
  • C++では参照かコピーかの区別がある。明示しなければキャプチャできない。
  • C++では変数ごとに参照かコピーかの指示もできる。