如何实现最简单的C ++可调用对象包装器?

时间:2012-11-05 16:22:40

标签: c++ c++11 function-pointers functor

我想实现一个类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;
}

我的问题是:如何在PURE C ++中实现类FuncWrapper(即没有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;
};

2 个答案:

答案 0 :(得分:3)

好的,你可能认为做你正在尝试的事情很简单,但这很复杂。

在您的情况下,您希望能够添加仿函数以及实际函数,这就是使事情复杂化的原因。毕竟,如果你的类将构造函数带到一个名为Functor的仿函数,那么你将在哪里存储对象?

boost在其共享指针类中用于存储删除器的一种方法实际上是具有基类和派生类。您的构造函数将构造一个派生自基类的对象(使用new),然后使用多态来调用。

boost在其函数和binder / 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 );
     }
};

所以现在你看到了存储函子的位置..

答案 1 :(得分:0)

只需向您的仿函数添加一个构造函数,该构造函数接受指向函数的指针(具有您想要的函数签名)。将指针存储在仿函数中,并从operator()执行指向函数。

如果我理解正确,你需要一个包装器,它将为仿函数和函数提供类似函数的行为。将指针存储到包装器中的仿函数而不是指向函数的指针。使用仿函数作为参数的构造函数将把仿函数存储在里面。使用func作为参数的构造函数将创建一个仿函数(就像我在答案中写的那样)并将其存储在里面。