C++11におけるstd::functionとstd::bindの実践的活用

関数ポインタの代替としてC++11で導入されたstd::functionは、()演算子で呼び出せるあらゆる呼び出し可能オブジェクトを汎用的に保持可能です。

以下はstd::functionを用いた配列フィルタリングの例です。

void displayFilteredValues(const std::vector<double>& data, std::function<bool(double)> checker) {
    for (const auto& value : data) {
        if (checker(value)) {
            std::cout << value << std::endl;
        }
    }
}

この関数は、checkerに渡された条件に合致する要素を出力します。例えば:

std::vector<double> values = {1.5, 2.3, 4.0, 5.7};
displayFilteredValues(values, [](double v) { return v > 3.0; });  // 3.0を超える値を出力
displayFilteredValues(values, [](double v) { return std::fmod(v, 2.0) == 0.0; });  // 偶数値を出力

std::functionはクロージャーを介してローカル変数を保持することも可能です。

void computeStats(std::vector<double>& values, std::function<void()>& resultPrinter) {
    double sum = 0.0;
    for (const auto& v : values) sum += v;
    double avg = sum / values.size();
    
    resultPrinter = [avg]() {
        std::cout << "Average: " << avg << std::endl;
    };
}

この例ではresultPrinteravgをキャプチャし、後続の呼び出しで平均値を出力します。

std::bindは関数呼び出し時に一部の引数を事前に固定する際に利用されます。

bool isInRange(double val, double low, double high) {
    return (val >= low) && (val <= high);
}

// 25.0~45.0の範囲をフィルタリング
auto rangeFilter = std::bind(isInRange, std::placeholders::_1, 25.0, 45.0);
displayFilteredValues(values, rangeFilter);

std::placeholders::_1は実引数の最初の位置を示します。複数のプレースホルダーを使用する場合は_2_3などと指定します。

クラスメンバ関数のコールバック実装例:

class DataViewer {
private:
    double min_val;
    double max_val;
public:
    DataViewer(double min, double max) : min_val(min), max_val(max) {}
    void showRange() const {
        std::cout << "Range [" << min_val << ", " << max_val << "]" << std::endl;
    }
};

void executeCallback(std::function<void()> callback) {
    callback();
}

// メンバ関数をバインド
DataViewer viewer(10.5, 89.2);
auto callback = std::bind(&DataViewer::showRange, viewer);
executeCallback(callback);

メンバ関数をstd::bindする際は、オブジェクトインスタンスを明示的に渡す必要があります。

タグ: C++11 std::bind lambda-capture function-object

5月24日 04:11 投稿