4

私はファンクターで遊んでいます。以下の標準的な例を使用しています。

class C {
public:
    template <typename Func>
    void foo(Func fun)
    {
        fun();
    }
};

struct S {
    void operator()() { printf ("in S\n"); }
};
....
C myClass;
myClass.foo (S());

これはうまく機能し、foo() の呼び出しで S テンプレート型を明示的に指定する必要はありません。しかし、ファンクターをメンバー変数として保存し、後で呼び出すとします。

class C {
public:
    template <typename Func>
    void foo(Func fun) {
        _myFunc = fun;
    }

    void someOtherThing() { 
        _myFunc();
    }
private:
    WHAT_IS_THIS_TYPE _myFunc;
};

クラス全体をテンプレートにする必要がありますか? もしそうなら、コンパイラは単一のファンクターで行ったようにテンプレートの型を推測できますか、それとも明示的に提供する必要がありますか? ありがとう。

4

2 に答える 2

4

std::function (C++11 の場合) または boost::function を使用して、呼び出し可能なオブジェクト (関数、ファンクター) を格納できます。型消去パターンを実装しています。

class C {
public:
  template <typename Func>
  void foo(Func fun) {
    _myFunc = fun;
  }

  void someOtherThing() { 
    _myFunc();
  }
private:

  std::function<void()> _myFunc;
};
于 2013-09-18T10:58:57.573 に答える
-1

Cクラスをテンプレートにすることを避けるための手作りの方法は次のとおりです。

struct C {
    template <typename Func>
    void foo(Func fun) {
        _myFunc = static_cast <void*>(&fun);
        stub = call <Func>;
    }

    void someOtherThing() {
        stub(_myFunc);
    }

private:
    void* _myFunc;
    void (*stub)(void*);

    template <typename F>
    static void call(void* f) {
        (*static_cast <F*>(f))();
    }
};

struct S {
    void operator()() { std::cout << "in S" << std::endl; }
};

int main()
{
    S s;
    C myClass;
    myClass.foo(s);
    myClass.someOtherThing();
}

を呼び出すとfoo()、型Funcはテンプレート静的関数内に「格納」されます。callこれは、に格納されている (のインスタンス化) へのポインタstubです。後者はsomeOtherThing実際に呼び出すためにによって呼び出されます_myFuncが、これは単純なものにすぎませんvoid*。これを行うには、最初に を正しい型にキャストし直します。これは、の本体_myFunc内でのみ認識されます。call

唯一の問題は、関数へのポインターを使用すると、stub(...)呼び出しのインライン化ができないことです。

于 2013-09-18T11:12:41.957 に答える