3

関数オブジェクトをクラスに渡したかったのですが、クラスは関数オブジェクトを使用してクラス内で何らかのジョブを実行します。

しかし、問題は、関数オブジェクトが渡されるものがわからないことです。したがってvoid *、クラスでポインターを定義すると、このポインターは、渡される関数オブジェクトで初期化されることがわかりました。

コードは以下のとおりです。

class A 
{
    public:
        //...
        void doSomeJob(int x)
        {
            (*functor)(x); //use the function object to process data x
        }

    private:
        //...
        void *functor; //function object's pointer will be assigned to this pointer
};

しかし、コードは機能しません。私は、void *functorそのように使用することはできません。

私は仕事を終えるために使うことができることを知っていますtemplate class、しかし私の質問は、私はまだ仕事を使うことができpointer to function objectますか、そしてどのようにですか?

PS

問題を明確にするために、データの処理方法が異なる関数オブジェクトがいくつかある可能性があります。どの関数オブジェクトが渡されるかはわかりませんが、それぞれがintパラメーターを受け取ることはわかっています。

いくつかの答えが示すように、私はを介して仕事をすることができますfunction pointerが、関数オブジェクトには、などの関数ポインターよりも多くのユーティリティがstatesあり、それを使用します。

4

4 に答える 4

9

タイプが呼び出し機構にアクセス可能な場所に格納されていない場合、呼び出しサイトで未知のタイプの関数オブジェクトを呼び出すことはできません。

2つのオプションがあります。

C ++ 11またはブーストを使用できる場合は、std::functionrespを使用できます。boost::function

class A
{
public:
  // ...
  void doSomeJob(int x)
  {
    functor(x);
  }
private:
  std::function<void(int)> functor; // or boost::function when using boost
};

ここで、タイプはfunctionテンプレートのメカニズム内に(暗黙の形式で)格納されます。

それ以外の場合、渡されるすべての関数オブジェクトが特定の基本クラスから派生したクラスタイプを持つことを要求できる場合は、抽象基本クラスを作成できます。

struct AbstractFunctor
{
  virtual void operator()(int) = 0;
};

class A
{
public:
  // ...
  void doSomeJob(int x)
  {
    (*functor)(x);
  }
private:
  AbstractFunctor* functor; // or boost::function when using boost
};

ここで、タイプは関数オブジェクトの仮想テーブルに格納されます。

本当にブーストを使用できない場合は、同様のソリューションを自分で作成することもできます。キーワードは「型消去」であり、基本的には、オブジェクトの型を認識して呼び出すことができる既知の基本クラス(私の2番目のソリューションのように)から派生オブジェクトをその場で生成することによって機能します。大まかに次のように実行される可能性があります(テストされていないコード)。

class int_function
{
private:
  struct abstract_forward
  {
    virtual void call(int) = 0;
    virtual abstract_forward clone() const = 0;
    virtual ~abstract_forward() {}
  };
  template<typename Functor> struct forward: abstract_forward
  {
    forward(Functor f): func(f) {}
    void call(int i) { func(i); }
    abstract_forward clone() const { return new forward<Functor>(func); }
    Functor func;
  };
public:
  template<typename Functor> int_function(Functor f)
  {
    forwarder = new forward<Functor>(f);
  }
  int_function(int_function const& other)
  {
    forwarder = other.forwarder->clone();
  }
  int_function& operator=(int_function const& other)
  {
    abstract_forward* newfwd = other.forwarder->clone();
    delete forwarder;
    forwarder = newfwd;
  }
  ~int_function()
  {
    delete forwarder}
  }
  void operator()(int i)
  {
    forwarder->call(i);
  }
private:
  abstract_forward* forwarder;
};

class A
{
public:
  void doSomeJob(int x)
  {
    functor(x);
  }
private:
  int_function functor;
};
于 2012-01-15T09:46:26.007 に答える
2
void *functor; //function object's pointer will be assigned to this pointer

これは関数ポインタではありません。

必要なのはこれです:

void (*functor)(int); //function pointer

さらに良いのはこれです(C ++ 11の場合):

#include <functional> //must include this 

std::function<void(int)> functor;

//then use it as:
functor(x);  //not (*functor)(x)
于 2012-01-15T09:40:33.010 に答える
1

正しい構文は次のとおりです。

void (*functor)(int);

関数ポインタの宣言と使用の詳細については、次のチュートリアルも参照してください:http ://www.cprogramming.com/tutorial/function-pointers.html

于 2012-01-15T09:40:49.690 に答える
1

C ++はその型について非常に厳密であるため、void*関数ポインターとしてだけを使用することはできません。ポインタは、呼び出すための実際の関数ポインタである必要があります。

どの関数オブジェクトが渡されるかわからないというのはどういう意味ですか?その例では、intまたはをパラメーターとして受け取り、おそらく、たとえばをint&返すことがわかっているので、関数ポインターを次のように格納できます。void

void (*func)(int);

クラスメンバー関数、またはオーバーロードするクラスのインスタンスも格納できるようにしたい場合は、C ++11をoperator()使用std::functionしている場合はandfromを使用できます。または:std::bind<functional>boost::functionboost::bind

boost::function<void (int)> func;
于 2012-01-15T09:45:11.493 に答える