関数ラッパーの必要性
異なる呼び出し形式を持つ関数オブジェクトを統一的に扱うため、C++11ではstd::functionが提供されています。テンプレート関数の多重インスタンス化による効率低下を防ぐ効果があります。
#include <functional>
#include <iostream>
// 統一呼び出しインターフェース
template <typename F, typename T>
T applyCallable(F f, T x) {
static int counter = 0;
std::cout << "インスタンスカウント: " << ++counter << std::endl;
return f(x);
}
// 通常関数
double divide(double value) {
return value / 2;
}
// 関数オブジェクト
struct Divider {
double operator()(double value) const {
return value / 3;
}
};
int main() {
// 統一ラッパー生成
std::function<double(double)> wrappedFuncs[] = {
divide, // 通常関数
Divider(), // 関数オブジェクト
[](double d) { return d / 4; } // ラムダ式
};
for (const auto& func : wrappedFuncs) {
std::cout << applyCallable(func, 11.11) << std::endl;
}
return 0;
}
std::functionの実装例
#include <functional>
// 基本構文:戻り値型と引数型を指定
std::function<int(int, int)> createWrapper() {
struct Calculator {
int multiply(int a, int b) const { return a * b; }
};
// 静的関数バインディング
std::function<int(int, int)> ops[] = {
// 通常関数
[](int a, int b) { return a + b; },
// メンバ関数
&Calculator::multiply,
// オブジェクトインスタンス
Calculator()
};
return ops[0]; // 最適化されたシングルインスタンス
}
std::bindの応用
関数パラメータを固定したり、引数順序を調整するアダプタ機能を提供します。
#include <functional>
#include <algorithm>
#include <vector>
// プレースホルダー定義
using namespace std::placeholders;
// パラメータ調整例
void processData(int a, int b, int c) {
std::cout << "A:" << a << " B:" << b << " C:" << c << std::endl;
}
int main() {
// 引数固定と順序調整
auto adapter = std::bind(processData, _2, 42, _1);
// 逆順に呼び出し: C=10, A=20
adapter(20, 10); // 実際の引数は (A=20, C=10, B=42)
// コレクション操作に適用
std::vector<int> values = {1, 2, 3};
std::for_each(values.begin(), values.end(),
std::bind(processData, _1, _1, 0));
return 0;
}