本文へスキップ
BecomeCoder

C++コース · 第15章 アルゴリズムとラムダ式 ― 処理を短く安全に · レッスン63

std::function ― 関数を変数に持つ

ブラウザで完結

導入

ラムダやふつうの関数を「変数に入れて持ち回りたい」「関数を引数として受け取りたい」――そんなときの汎用の入れ物が std::function です。コールバックや、あとで差し替えられる処理を表すのに使います。

説明

function<戻り値(引数の型)> という形で、関数・ラムダをまとめて入れられます。中身が何であれ、同じ型の変数として扱えます。

#include <iostream>
#include <functional>   // std::function
using namespace std;

int addOne(int x) { return x + 1; }   // ふつうの関数

int main() {
    function<int(int)> f;

    f = addOne;                       // 関数を入れる
    cout << f(10) << endl;            // 11

    f = [](int x) { return x * 2; };  // ラムダも入れられる
    cout << f(10) << endl;            // 20
    return 0;
}

関数を引数に取る関数を書けば、「処理を後から渡す」設計ができます。ボタンが押されたときの動作など、コールバックの表現に向きます。

flowchart LR
  caller["呼び出し側"] -->|"処理を渡す"| api["void apply(vector, function&lt;...&gt; op)"]
  api -->|"各要素に op を適用"| result["結果"]
#include <iostream>
#include <vector>
#include <functional>
using namespace std;

// 「各要素にどうするか」を関数として受け取る
void each(const vector<int>& v, function<void(int)> action) {
    for (int x : v) action(x);
}

int main() {
    vector<int> v = {1, 2, 3};
    int sum = 0;
    each(v, [&sum](int x) { sum += x; });   // 処理を渡す
    cout << sum << endl;   // 6
    return 0;
}

まとめ

std::function<戻り値(引数)> は、関数・ラムダを入れられる汎用の入れ物です。「処理を変数に持つ」「処理を引数で受け取る」ことができ、コールバックや差し替え可能な設計に使います。テンプレート引数で受けるより柔軟ですが、少し実行コストがかかる点も覚えておきましょう。

実際に動かしてみよう

下のエディタにC++を書いて「コンパイル & 実行」を押すと、ブラウザ内で本物のC++コンパイラ(clang + libc++)がその場でコンパイルして実行し、出力が表示されます。std::string・vector・クラス・テンプレート・STL などモダンC++がそのまま動きます。本文の例を書き換えて試しながら進めましょう(初回だけコンパイラの読み込みに時間がかかります。以降はキャッシュされます。この回は標準入力(cin)は使わず、値はコードに直接書きます)。

C/C++ — ブラウザ内で本物のコンパイラで実行

ブラウザ内で本物のC/C++コンパイラ(clang + libc++ / WebAssembly)を動かします。構造体・malloc/free・std::string・vector・クラス・テンプレート・STL などがそのまま実行できます(初回のみコンパイラの読み込みに時間がかかります。以降はブラウザにキャッシュされます)。
スクロールして表示された時点でも自動で読み込まれます。