6

以下のプログラムも示すように、一般に、テンプレート引数は抽象クラスにすることができます。しかし、ソート中の比較ファンクターは抽象的であってはならないようです。少なくとも、以下はVC++11およびOracleStudio12ではコンパイルされません。

#include <vector>
#include <algorithm>


class Functor
{
public:
    virtual bool operator()(int a, int b) const = 0;
};


class MyFunctor: public Functor
{
public:
    virtual bool operator()(int a, int b) const { return true; }
};


int _tmain(int argc, _TCHAR* argv[])
{
    vector<Functor> fv; // template of abstract class is possible
    vector<int> v;
    MyFunctor* mf = new MyFunctor();
    sort(v.begin(), v.end(), *mf);
    Functor* f = new MyFunctor();
    // following line does not compile: 
    // "Cannot have a parameter of the abstract class Functor"
    sort(v.begin(), v.end(), *f); 
    return 0;
}

さて、これはファンクター引数の一般的なプロパティなのか、それともSTLの実装に依存するのか疑問に思います。私がやりたかったことを取得する方法はありますか?

4

3 に答える 3

13

ファンクターは通常、コピー可能である必要があります。多形ベースクラスは一般にコピー可能ではなく、抽象ベースは決してコピーできません。

更新: @ahendersonと@ltjaxによるコメントのおかげで、元のポリモーフィック参照を保持するラッパーオブジェクトを生成する非常に簡単な方法があります。

#include <functional>

std::sort(v.begin(), v.end(), std::ref(*f));
//                            ^^^^^^^^^^^^

の結果std::refは、std::refrence_wrapperまさに必要なものです。元のオブジェクトへの参照を保持する値セマンティクスを持つクラス。


ファンクターがコピーされるという事実は、ファンクター内に何かを蓄積したい多くの人々を捨てて、なぜ結果がオフになるのか疑問に思います。ファンクターは、実際には外部オブジェクトへの参照を取得する必要があります。ウィットに:

悪い!期待どおりに機能しません。ファンクターは任意にコピーされる可能性があります。

struct Func1 {
    int i;
    Func1() : i(0) { }
    void operator()(T const & x) { /* ... */ }
};

Func1 f;
MyAlgo(myContainer, f); 

良い例: アキュムレータを提供しますファンクターをコピーするのは安全です:

struct Func2 {
   int & i;
   Func2(int & n) : i(n) { }
   void operator()(T const & x) { /* ... */ }
};

int result;
MyAlgo(myContainer, Func2(result));
于 2012-09-13T14:08:57.547 に答える
5

Kerrekが言ったように、直接それを行うことはできません。

しかし、1レベルの間接参照で、問題ありません。

struct AbstractFunctor
{
  AbstractFunctor( Functor * in_f ): f(in_f) {}
  // TODO: Copy constructor etc.

  Functor * f;
  bool operator()(int a, int b) const { return (*f)(a,b); }
};

int main()
{
  vector<int> v;
  Functor * mf = new MyFunctor();
  sort(v.begin(), v.end(), AbstractFunctor(mf) );
}
于 2012-09-13T14:14:35.233 に答える
2

KerrekとMichaelAndersonが言ったように、直接それを行うことはできません。Michaelが示すように、ラッパークラスを作成できます。しかし、1つもありstd::ます:

sort(v.begin(),
     v.end(), 
     std::bind(&Functor::operator(),
               mf,
               std::placeholders::_1,
               std::placeholders::_2) );
于 2012-09-13T14:33:27.847 に答える