C++で無名関数の関数ポインタを作る

無名関数(ラムダとも呼ばれる)のメリットは大きい。

プログラミングで頭を悩ませるのは命名だ。プログラマが「名付け」を省略できるとコーディングの効率が大幅に上がり、命名ミスによって引き起こされる勘違い(バグ)もなくなる。

シグナルハンドラやqsort、スレッド生成等のAPIを使うときに関数ポインタを引数として渡す必要があるが、たとえそれが1度限りの再利用されない処理だとしてもわざわざ関数化する必要がある。こういう時はなおさら命名に困る。

更に悪いことに、その1度限りの関数は呼び出し元となる関数の外側に定義(実装)する必要があるためコードが分散してしまう。

最新のC++ではラムダが言語仕様として正式に規定されており単純な関数ポインタ以上の高度な機能を持っている。コンパイルオプションで-std=c++11などを使えばラムダを使用することができる。

コンパイルオプションを指定せずとも、無名関数を定義しその関数ポインタを得るだけであれば以下のようにすればよい。内部的にはC++structの機能を使用しているためCとしてはコンパイルできない。

無名関数を定義するマクロ

// 無名関数ポインタを返す。
// argumentsは括弧で囲った引数リスト。
// contentsは (({})) のように中括弧と2つの括弧で処理本体を囲う。
#define lambda(return_type, arguments, contents) ({ \
  struct { static return_type _ arguments { contents; } } _; _._; \
})

サンプル

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define lambda(return_type, arguments, contents) ({ \
  struct { static return_type _ arguments { contents; } } _; _._; \
})

int main()
{
  //
  // qsortの引数に無名関数を渡すサンプル
  //
  int data[] = {9, 2, 3, 6, 3, 2, 1, 3, 5, 7};
  qsort(data, 10, sizeof(int),
    lambda(int, (const void *a, const void *b), (({
      return *(int*)a - *(int*)b;
    })))
  );

  //
  // pthread_createの引数に無名関数を渡すサンプル
  //
  pthread_t tid;
  pthread_create(&tid, NULL,
    lambda(void *, (void *), (({
      puts("I'm thread.");
      return NULL;
    }))),
    NULL
  );
  return 0;
}