コンストラクターで作業を行うファンクタークラス
-
05-07-2019 - |
質問
C ++テンプレートを使用して、ストラテジーファンクターを渡し、関数の動作を変更しています。正常に動作します。私が渡すファンクターは、ストレージのないステートレスクラスであり、古典的なファンクターの方法で()演算子をオーバーロードするだけです。
template <typename Operation> int foo(int a)
{
int b=Operation()(a);
/* use b here, etc */
}
私はこれを頻繁に行いますが、うまく機能します。また、6個または7個のテンプレート化されたファンクターが渡されたテンプレートを作成することもよくあります!
ただし、コードの優雅さと効率の両方を心配しています。ファンクターはステートレスであるため、Operation()コンストラクターは無料であり、ファンクターの評価はインライン関数と同じくらい効率的であると想定していますが、すべてのC ++プログラマーと同様に、私は常にいくつかの疑わしい疑問を持っています。
2番目の質問は、代替ファンクターアプローチを使用できるかどうかです。()演算子をオーバーライドせず、副作用としてコンストラクター内のすべてを実行するアプローチです。 次のようなもの:
struct Operation {
Operation(int a, int &b) { b=a*a; }
};
template <typename Operation> int foo(int a)
{
int b;
Operation(a,b);
/* use b here, etc */
}
&quot; work&quot;としてコンストラクタを使用する人を見たことはありません。ファンクタの、しかしそれは動作するはずのようです。利点はありますか?欠点はありますか?奇妙な二重括弧&quot; Operator()(a)&quot;の削除が好きです。 、しかしそれはおそらく美学です。
解決
デメリットはありますか
- Ctorsは有用な値を返しません-連鎖呼び出しでは使用できません(例:foo(bar())。
- 投げることができます。
- デザインの観点-アクターはオブジェクト作成関数であり、実際には主力者ではありません。
他のヒント
- 実際には、コンパイラはOperationの空のコンストラクターをインライン化します(最適化をオフにした場合を除き、少なくとも同様の状況ではgccが行います)
- コンストラクタですべてを行うことの欠点は、このように内部状態を持つファンクタを作成できないことです。述語を満たす要素の数を数えるためのファンクター。また、実際のオブジェクトのメソッドをファンクターとして使用すると、後で実行するためにそのインスタンスを格納できます。これは、コンストラクターアプローチでは実行できません。
パフォーマンスの観点から、コードはVCとGCCの両方で完全に最適化されています。ただし、多くの場合、ファンクターをパラメーターとして使用する方がより優れた戦略です。この方法により、柔軟性と同一のパフォーマンス特性を得ることができます。
STLコンテナで動作するファンクタを定義することをお勧めします。つまり、operator()を実装する必要があります。 (使用している言語のAPIに従うことは常に良い考えです。)
これにより、アルゴリズムが非常に汎用的(関数、ファンクター、stl-bind、boost :: function、boost :: bind、boost :: lambda、...)になります。 p>
この方法では、ファンクタータイプをテンプレートパラメーターとして指定する必要はなく、インスタンスを構築して渡すだけです:
my_algorithm(foo, bar, MyOperation())
コンストラクタを別のクラスに実装する意味はありません。
あなたがしているのは、カプセル化を解除し、クラスを不正使用に設定することです。
コンストラクタは、オブジェクトをクラスによって定義された良好な状態に初期化することになっています。別のオブジェクトによるクラスの初期化を許可しています。このテンプレートクラスがクラスを正しく初期化する方法を知っているという保証はありますか?クラスのユーザーは、意図しない方法でオブジェクトの内部状態を混乱させる可能性のあるオブジェクトを提供できます。
クラスは自己完結型であり、適切な状態に初期化する必要があります。あなたがしているように見えるのは、テンプレートで何ができるかを見るためだけに遊んでいるということです。