C++ファンクター解説(例コード付き)
C++のファンクターとその用途の解説
ファンクターとは?
C++のファンクター(functor)とは、関数オブジェクト(function object)とも呼ばれ、関数のように呼び出すことができるオブジェクトです。クラスのインスタンスであり、演算子オーバーロード (operator()
) を実装することで、関数のように呼び出すことができます。
ファンクターの用途
ファンクターは、さまざまな場面で活用されます。以下に主な用途を挙げます。
アルゴリズムの汎化:
- STL(Standard Template Library)の多くのアルゴリズムは、ファンクターを受け取ることで、さまざまな条件や操作を適用できます。
- 例えば、
std::sort
関数では、比較演算子を定義するファンクターを渡すことで、任意の要素を昇順または降順にソートできます。
遅延評価:
カスタマイズ可能な演算子:
#include <iostream>
#include <algorithm>
#include <vector>
// 比較演算子をオーバーロードしたファンクター
struct GreaterThan {
bool operator()(int a, int b) const {
return a > b;
}
};
int main() {
std::vector<int> numbers = {3, 1, 4, 1, 5, 9};
// ファンクターを使用してソート
std::sort(numbers.begin(), numbers.end(), GreaterThan());
// ソート結果を表示
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
}
この例では、GreaterThan
というファンクターを定義し、std::sort
関数に渡しています。これにより、ベクトル numbers
を降順にソートすることができます。
C++ファンクター解説(例コード付き)
比較演算子オーバーロード
#include <iostream>
#include <algorithm>
#include <vector>
// 比較演算子をオーバーロードしたファンクター
struct GreaterThan {
bool operator()(int a, int b) const {
return a > b;
}
};
int main() {
std::vector<int> numbers = {3, 1, 4, 1, 5, 9};
// ファンクターを使用してソート
std::sort(numbers.begin(), numbers.end(), GreaterThan());
// ソート結果を表示
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
}
- 解説: この例では、
GreaterThan
というファンクターを定義し、比較演算子 (operator()
) をオーバーロードしています。このファンクターは、2つの整数を受け取り、その大小関係を比較して、大きい値が true、小さい値が false を返します。 - 用途:
std::sort
関数にこのファンクターを渡すことで、ベクトルnumbers
を降順にソートすることができます。
カスタム演算子
#include <iostream>
struct Matrix {
int data[3][3];
// 行列の掛け算
Matrix operator*(const Matrix& other) const {
Matrix result;
// 行列の掛け算の計算を省略
return result;
}
};
int main() {
Matrix A, B, C;
// 行列の初期化を省略
// ファンクターとして行列の掛け算を使用
C = A * B;
}
- 解説: この例では、
Matrix
構造体を定義し、行列の掛け算演算子 (operator*
) をオーバーロードしています。これにより、行列の掛け算を直接演算子として使用することができます。 - 用途: 行列の演算をより自然な形で表現することができます。
遅延評価
#include <iostream>
struct Calculator {
int x, y;
Calculator(int x, int y) : x(x), y(y) {}
int calculate() const {
return x * x + y * y;
}
};
int main() {
Calculator calc(3, 4);
// 実際に計算するまで評価されない
int result = calc.calculate();
std::cout << result << std::endl;
}
- 解説: この例では、
Calculator
構造体を定義し、計算を遅延させるためのcalculate
メソッドを実装しています。 - 用途: 計算コストの高い操作を必要に応じて遅延させる場合に便利です。
C++ファンクターの代替手法
C++のファンクターは、関数オブジェクトとしてさまざまな用途で使用されます。しかし、ファンクター以外の代替手法も存在します。以下に、そのいくつかを紹介します。
ラムダ式
ラムダ式は、匿名関数として定義される C++11 以降の言語機能です。ファンクターと同様に、関数オブジェクトとして使用することができます。
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> numbers = {3, 1, 4, 1, 5, 9};
// ラムダ式を使用してソート
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a > b;
});
// ソート結果を表示
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
}
この例では、ラムダ式を使用して比較演算子を定義し、std::sort
関数に渡しています。ファンクターと同様に、ラムダ式は匿名関数として定義され、関数オブジェクトとして使用できます。
関数ポインタ
関数ポインタは、関数のアドレスを保持するポインタです。関数を関数オブジェクトとして使用する場合、関数ポインタを使用することもできます。
#include <iostream>
#include <algorithm>
#include <vector>
bool greaterThan(int a, int b) {
return a > b;
}
int main() {
std::vector<int> numbers = {3, 1, 4, 1, 5, 9};
// 関数ポインタを使用してソート
std::sort(numbers.begin(), numbers.end(), greaterThan);
// ソート結果を表示
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
}
この例では、greaterThan
関数を定義し、そのアドレスを関数ポインタに割り当てています。その後、この関数ポインタを std::sort
関数に渡すことで、ソートを行うことができます。
std::function
std::function
テンプレートクラスは、任意の呼び出し可能なオブジェクトを保持することができます。ファンクター、ラムダ式、関数ポインタなどを std::function
オブジェクトに格納し、関数オブジェクトとして使用することができます。
#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>
int main() {
std::vector<int> numbers = {3, 1, 4, 1, 5, 9};
// std::functionを使用してソート
std::function<bool(int, int)> compare = [](int a, int b) {
return a > b;
};
std::sort(numbers.begin(), numbers.end(), compare);
// ソート結果を表示
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
}
この例では、ラムダ式を std::function
オブジェクトに格納し、std::sort
関数に渡しています。std::function
は、ファンクター、ラムダ式、関数ポインタなどのさまざまな呼び出し可能なオブジェクトを統一的に扱うことができます。
c++ functor function-object