1.関数オブジェクトの概念
関数オブジェクトの概念に関して言えば、誰もが比較的なじみがないかもしれませんが、最初に、使い慣れたC言語の関数ポインターから始めましょう。
次の図に示すように、sum関数も実装しています。1つはC言語の関数ポインターで実装され、もう1つはC ++のオブジェクトで実装されています。
違いを確認するには、左側のC言語実装が関数です。アドレスと次のC ++の方法はsumオブジェクトで渡され、そのオブジェクトは演算子関数を呼び出すことによって関数を実現します。
これから、関数オブジェクトの具体的な概念を与えることができます。
演算子()かっこ演算子のオーバーロード関数を持つオブジェクトは、関数オブジェクトまたはファンクターと呼ばれます
第二に、関数オブジェクトの利点
(1)バージョン1を比較する:
template<typename T>
bool compare(T a, T b)
{
return a > b;
}
int main()
{
cout << compare(10, 20) << endl;
cout << compare('b', 'y') << endl;
return 0;
}
上記の関数の実装を詳しく見ると、それについて考えることができます。ライブラリの関数を頻繁に変更することはないため、C言語の関数ポインターの解決につながります
(2)C関数ポインタソリューションを使用する
template<typename T>
bool mygreater(T a, T b)
{
return a > b;
}
template<typename T>
bool myless(T a, T b)
{
return a < b;
}
template<typename T,typename Compare>
bool compare(T a, T b, Compare comp)
{
return comp(a, b);
}
int main()
{
cout << compare(10, 20, mygreater<int>) << endl;
cout << compare(10, 20, myless<int>) << endl;
return 0;
}
実行結果は次のとおりです。
上記の関数の実現を注意深く観察します。関数ポインターを介して関数呼び出しをインライン化する方法はありません。関数呼び出しのオーバーヘッドのため、効率は非常に低くなります。
実行時に関数ポインターが呼び出されるため、インライン関数として呼び出される関数を作成することはできませんが、インライン関数はコンパイル時に展開する必要があります。
これから、関数オブジェクトのソリューションを導き出しました
(3)C ++関数オブジェクトバージョンの実装
template<typename T>
class mygreater
{
public:
bool operator()(T a, T b)
{
return a > b;
}
};
template<typename T>
class myless
{
public:
bool operator()(T a, T b)
{
return a < b;
}
};
int main()
{
//此时传入的是两个对象而不是函数的地址
cout << compare(10, 20, mygreater<int>()) << endl;
cout << compare(10, 20, myless<int>()) << endl;
return 0;
}
利点は、オブジェクト機能:
関数オブジェクトのオペレータによる1つのコール()、あなたはオーバーヘッドを省略関数を呼び出すことができます
コンパイルプロセスの非常に明確な呼び出しであるオブジェクトの機能を、これ作る使用の関数オブジェクトは完全にインラインである、州関数呼び出しのオーバーヘッドを削除
2.関数オブジェクトはクラスによって生成されるため、関数オブジェクトが使用されたときに、関連するメンバー変数を追加して、より多くの情報を記録できます。
たとえば、このオブジェクトが呼び出された回数を記録する場合は、プライベートメンバーでカウントメンバー変数countを定義できます。
第三に、関数オブジェクトの適用
アプリケーション1:優先キュー
優先度キューでは、デフォルトは大きなルートヒープですが、基になる比較メソッドを変更して小さなルートヒープを実現できます。コードは次のとおりです。
int main()
{
priority_queue<int> que1;//默认的是大根堆
for (int i = 0; i < 10; i++)
{
que1.push(rand() % 100);
}
while (!que1.empty())
{
cout << que1.top() << " ";
que1.pop();
}
cout << endl;
//小根堆 改变底层比较的方式
using MinHeap = priority_queue<int, vector<int>, greater<int>>;
MinHeap que2;
for (int i = 0; i < 10; i++)
{
que2.push(rand() % 100);
}
while (!que2.empty())
{
cout << que2.top() << " ";
que2.pop();
}
cout << endl;
return 0;
}
アプリケーション2:セット
はシステムのデフォルトで、セットは少ないです。大から小への配置を実装しましょう
int main()
{
set<int,greater<int>> set1;
for (int i = 0; i < 10; i++)
{
set1.insert(rand() % 100);
}
for (int v : set1)
{
cout << v << " ";
}
cout << endl;
return 0;
}