4

以下のように動作するFuncWrapperクラスを実装したいのですが、思ったほど簡単ではありません。

int OrdinaryFunction(int n)
{
    return n;
}

struct Functor
{
    int operator ()(int n)
    {
        return n;
    }
};

int main()
{
    FuncWrapper<int(int)> f1(OrdinaryFunction);
    cout << f1(1); // output 1;

    Functor functor;
    FuncWrapper<int(int)> f2(functor);
    cout << f2(2); // output 2;

    return 0;
}

私の質問は次のとおりです。コードをコンパイルするために、クラスFuncWrapperをPURE C ++(つまり、STLなし)で実装するにはどうすればよいですか?

以下に示すFuncWrapperを部分的に実装しました。

template<class T>
class FuncWrapper;

template<class ReturnType, class Parameter1>
class FuncWrapper<ReturnType(Parameter1)>
{
public:
    typedef ReturnType (*FunctionPtr)(Parameter1);

    template<class Functor>
    FuncWrapper(Functor fn) 
    {
        // ???
    }

    FuncWrapper(FunctionPtr fn)
        : fn(fn)
    {}

    ReturnType operator ()(Parameter1 p1)
    {
          return this->fn(p1);          
    }

private:
    FunctionPtr fn;
};
4

2 に答える 2

3

さて、あなたはあなたがしようとしていることをするのは簡単だと思うかもしれませんが、それは非常に複雑です。

あなたの場合、実際の関数だけでなくファンクターも追加できるようにしたいのですが、それが事態を複雑にします。結局のところ、クラスがFunctorというファンクターにコンストラクターを持っていく場合、オブジェクトをどこに格納しますか?

共有ポインタクラスでブーストが削除機能を格納するために使用する1つのメソッドは、実際に基本クラスと派生クラスを持つことです。コンストラクターは、基本クラスから派生するオブジェクト(newを使用)を構築し、ポリモーフィズムを使用して呼び出します。

boostは、関数およびバインダー/ mplライブラリであらゆる種類の巧妙な手法を使用していますが、今のところ、これを使用することをお勧めします。

Boostやその他の種類の共有ポインタを使用することに本当に反対している場合は、このオブジェクトのメモリを管理する必要があります。(外部クラスをコピー可能で割り当て可能にしたいので面倒です)。

簡単にして、shared_ptrを使用できると言います。また、今のところ署名を単純化するつもりです。

概要として...

template< typename R, typename P > class FunctorBase
{
 public:
      virtual ~FunctorBase() {}
      virtual R call(P p) = 0;
};

template< typename R, typename P > class FunctionWrapper
{
     shared_ptr< FunctorBase< R, P > > impl;
  public:
     template< typename F > // a functor
     FunctionWrapper( Functor f )
     {
          // create appropriate impl for functors
     }

     FunctionWrapper( (R (func*)(P) )
     {
          // create appropriate impl for functions
     }

     R operator()( P p )
     {
          return impl->call(p);
     }
};

ファンクターの実装は次のようになります。

template< typename R, typename P, typename F >
class FunctorImpl : public FunctorBase< R, P >
{
    F f;

   public: 
     FunctorImpl( F fparam ) : f( fparam )
     {
     }

     R call( P p )
     {
        return f( p );
     }
};

これで、ファンクターをどこに保存できるかがわかります。

于 2012-11-05T17:08:36.260 に答える
0

関数へのポインターを受け入れるコンストラクターをファンクターに追加するだけです(必要な関数シグネチャーを使用)。ファンクターにポインターを格納し、演算子()から指定された関数を実行します。

私があなたを正しく理解しているなら、ファンクターと関数の両方に対して関数のような振る舞いを公開するラッパーが必要です。関数へのポインターではなく、ファンクターへのポインターをラッパーに格納します。ファンクターをパラメーターとして持つコンストラクターは、ファンクターを内部に格納します。パラメーターとしてfuncを使用するコンストラクターは、(回答で書いたように)ファンクターを作成し、その中に格納します。

于 2012-11-05T16:31:47.063 に答える